JDBC接口---01概述

本文详细介绍了Java JDBC的概念、体系结构和使用步骤,包括如何加载注册驱动、建立数据库连接以及使用Statement和PreparedStatement执行SQL。强调了PreparedStatement在防止SQL注入方面的优势,并给出了ResultSet的使用及元数据获取。最后展示了一个通用的数据库查询方法示例。
摘要由CSDN通过智能技术生成


一、JDBC概述

Java中的数据存储技术:
在Java中,数据库存取技术可分为如下几类:

  1. JDBC直接访问数据库
  2. JDO技术
  3. 第三方O/R工具,如Hibernate, mybatis 等

  JDBC是java访问数据库的基石,JDO, Hibernate等只是更好
的封装了JDBC

  JDBC是一个独立于特定数据库管理系统、通用的SQL数据库存取和操作的公共接口(一组API),定义了用来访问数据库的标准Java类库,(java.sql,javax.sql)使用这个类库可以以一种
标准的方法、方便地访问数据库资源

  JDBC为访问不同的数据库提供了一种统一的途径,为开发者屏蔽了一些细节问题。

  JDBC的目标是使Java程序员使用JDBC可以连接任何提供了JDBC驱动程序的数据库系统,这样就使得程序员无需对特定的数据库系统的特点有过多的了解,从而大大简化和加快了开发过程

没有使用JDBC接口时的连接:
没有使用JDBC时

使用JDBC连接后:
在这里插入图片描述

二、JDBC体系结构

JDBC接口(API)包括两个层次:
  面向应用的API:Java API,抽象接口,供应用程序开发人员使用(连接数据库,
执行SQL语句,获得结果)。
  面向数据库的API:Java Driver API,供开发商开发数据库驱动程序用。

面向接口编程:
  JDBC是sun公司提供一套用于数据库操作的接口,java程序员只需要面向这套接口编程即可。
不同的数据库厂商,需要针对这套接口,提供不同实现。不同的实现的集合,即为不同数据库的
驱动。

  JDBC API 是一系列的接口,它使得应用程序能够进行数据库联接,执行
SQL语句,并且得到返回结果

JDBC程序访问数据库步骤

在这里插入图片描述

获取数据库连接

四要素:

  1. Driver接口实现类
  2. URL:JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
  3. 用户名和密码

1、Driver 接口

  java.sql.Driver 接口是所有 JDBC 驱动程序需要实现的接口。这个接口是提
供给数据库厂商使用的,不同数据库厂商提供不同的实现
  在程序中不需要直接去访问实现了 Driver 接口的类,而是由驱动程序管理
器类(java.sql.DriverManager)去调用这些Driver实现
Oracle的驱动:oracle.jdbc.driver.OracleDriver
mySql的驱动: com.mysql.jdbc.Drive

2、加载与注册 JDBC 驱动

方式一:加载 JDBC 驱动需调用 Class 类的静态方法 forName(),向其传
递要加载的 JDBC 驱动的类名

Class.forName(“com.mysql.jdbc.Driver”);

方式二:DriverManager 类是驱动程序管理器类,负责管理驱动程序

DriverManager.registerDriver(com.mysql.jdbc.Driver);

  通常不用显式调用 DriverManager 类的 registerDriver() 方法来注册驱动程序类的实例,因为 Driver 接口的驱动程序类都包含了静态代码块,在这个静态代码块中,会调用 DriverManager.registerDriver() 方法来注册自身的一个实

3、建立连接(Connection)

  • 可以调用 DriverManager 类的 getConnection() 方法建立到数据库的连接
  • User,password可以用“属性名=属性值”方式告诉数据库;
  • JDBC URL 用于标识一个被注册的驱动程序,驱动程序管理器通过这个 URL 选择正确的驱动程序,从而建立到数据库的连接。
  • JDBC URL的标准由三部分组成,各部分间用冒号分隔。
    jdbc:子协议:子名称
    协议:JDBC URL中的协议总是jdbc
    子协议:子协议用于标识一个数据库驱动程序
    子名称:一种标识数据库的方法。子名称可以依不同的子协议而变化,用子名称的目的是为了定位数据库提供足够的信息。包含主机名(对应服务端的ip地址),端口号,数据库名
    在这里插入图片描述

几种常用数据库的JDBC URL
1、对于 Oracle 数据库连接,采用如下形式:

jdbc:oracle:thin:@localhost:1521:atguigu

2、对于 SQLServer 数据库连接,采用如下形式:

jdbc:microsoft:sqlserver//localhost:1433; DatabaseName=sid

3、对于 MYSQL 数据库连接,采用如下形式:

jdbc:mysql://localhost:3306/atguigu

案例代码:将数据库连接需要的4个基本信息声明在配置文件中,通过读取配置文件的方式获取连接

 @Test
    public void testConnection5() throws SQLException, IOException, ClassNotFoundException {
        //1、读取配置文件中的4个基本信息
        InputStream is = Connection.class.getClassLoader().getResourceAsStream("jdbc.properties");
        Properties pros = new Properties();
        pros.load(is);
        //2、读取配置信息
        String user = pros.getProperty("user");
        String password = pros.getProperty("password");
        String url = pros.getProperty("url");
        String driverClass = pros.getProperty("driverClass");
        //2、加载驱动
        Class.forName(driverClass);
        //3、获取连接
        Connection conn = (Connection) DriverManager.getConnection(url, user, password);
        System.out.println(conn);
    }

jdbc.properities

user=root
password=******
url=jdbc:mysql://localhost:3306/test
driverClass=com.mysql.jdbc.Driver

使用Statement操作数据表的弊端

访问数据库

  数据库连接被用于向数据库服务器发送命令和 SQL 语句,在连接建立
后,需要对数据库进行访问,执行 sql 语句 在 java.sql 包中有 3 个接口分别定义了对数据库的调用的不同方式:

  • Statement
  • PreparedStatement
    • CallableStatement

SQL 注入攻击

  SQL 注入是利用某些系统没有对用户输入的数据进行充分的检查,而在用户输入数据中注入非法的 SQL 语句段或命令(如:SELECT user, password FROM user_table WHERE user=‘a’ OR 1 = ’ AND password = ’ OR ‘1’ = ‘1’) ,从而利用系统的 SQL 引擎完成恶意行为的做法
  对于 Java 而言,要防范 SQL 注入,只要用 PreparedStatement(从Statement扩展而来) 取代 Statement 就可以了

使用PreparedStatemen

1、通过调用 Connection 对象的 preparedStatement() 方法获取PreparedStatement 对象
2、PreparedStatement 接口是 Statement 的子接口,它表示一条预编译过的SQL 语句
3、PreparedStatement 对象所代表的 SQL 语句中的参数用问号(?)来表示,调用 PreparedStatement 对象的 setXxx() 方法来设置这些参数. setXxx() 方法有两个参数

  • 第一个参数是要设置的 SQL 语句中的参数的索引(从 1 开始)
  • 第二个是设置的 SQL 语句中的参数的值

PreparedStatement 和 Statement

  1. 代码的可读性和可维护性.
  2. PreparedStatement 能最大可能提高性能:

  DBServer会对预编译语句提供性能优化。因为预编译语句有可能被重复调用,所以语句在被DBServer的编译器编译后的执行代码被缓存下来,那么下次调用时只要是相同的预编译语句就不需要编译,只要将参数直接传入编译过的语句执行代码中就会得到执行。

  在statement语句中,即使是相同操作但因为数据内容不一样,所以整个语句本身不能匹配,没有缓存语句的意义.事实是没有数据库会对普通语句编译后的执行代码缓存.这样每执行一次都要对传入的语句编译一次.

  3. PreparedStatement 可以防止 SQL 注入

连接数据库操作表的步骤;

  1. 注册驱动 (只做一次)
  2. 建立连接(Connection)
  3. 创建执行SQL的语句(Statement)
  4. 执行语句
  5. 处理执行结果(ResultSet)
  6. 释放资源

关于ResultSet的说明

  • 查询需要调用Prepared Statement 的 executeQuery() 方法,查询结果是一个 ResultSet对象
  • 关于 ResultSet:代表结果集

ResultSet: 结果集. 封装了使用 JDBC 进行查询的结果.

调用 PreparedStatement 对象的 executeQuery() 可以得到结果集.

ResultSet 返回的实际上就是一张数据表. 有一个指针指向数据表的第一条记录的前面.

  • 可以调用 next() 方法检测下一行是否有效. 若有效该方法返回 true, 且指针下移. 相当于Iterator 对象的
    hasNext() 和 next() 方法的结合体
  • 当指针指向一行时, 可以通过调用 getXxx(int index) 或 getXxx(int columnName) 获取每一列的值.

例如: getInt(1), getString(“name”)

  • ResultSet 当然也需要进行关闭.

ResultSetMetaData 类

可用于获取关于 ResultSet 对象中列的类型和属性信息的对象
ResultSetMetaData meta = rs.getMetaData();

方法描述
getColumnName(int column)获取指定列的名称
getColumnLabel(int column)获取指定列的别名
getColumnCount()返回当前 ResultSet 对象中的列数
getColumnTypeName(int column)检索指定列的数据库特定的类型名称
getColumnDisplaySize(int column)指示指定列的最大标准宽度,以字符为单位
isNullable(int column)指示指定列中的值是否可以为 null
isAutoIncrement(int column)指示是否自动为指定列进行编号,这样这些列仍然是只读的

案例代码:

    //针对于不同表通用的查询操作,返回表中的一条记录
    public <T> T getInstance(Class<T> clazz, String sql, Object... args) {
        com.mysql.jdbc.Connection conn = null;
        PreparedStatement ps = null;
        ResultSet rs = null;
        try {
            //1、获取连接
            conn = JDBCUtils.getConnection();
		//2、执行SQL语句
            ps = conn.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                ps.setObject(i + 1, args[i]);
            }
            rs = ps.executeQuery();
            //3、获取结果集的元数据 :ResultSetMetaData
            ResultSetMetaData rsmd = rs.getMetaData();
            //4、通过ResultSetMetaData获取结果集中的列数
            int columnCount = rsmd.getColumnCount();

            if (rs.next()) {
                //accounttest cust = new accounttest();
                T t = clazz.newInstance();
                //处理结果集一行数据中的每一个列
                for (int i = 0; i < columnCount; i++) {
                    //获取列值
                    Object columValue = rs.getObject(i + 1);

                    //获取每个列的列名(不推荐使用)
//					String columnName = rsmd.getColumnName(i + 1);
                    //获取类的别名
                    String columnLabel = rsmd.getColumnLabel(i + 1);

                    //给cust对象指定的columnName属性,赋值为columValue:通过反射
                    Field field = clazz.getDeclaredField(columnLabel);
                    field.setAccessible(true);
                    field.set(t, columValue);
                }
                return t;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
        //关闭资源
            JDBCUtils.closeResource(conn, ps, rs);
        }
        return null;
    }

   @Test
    public void testGetForList() {
        String sql= "select id,username from account where id>?";
        List<accounttest> list = getForList(accounttest.class, sql, 13);
        list.forEach(System.out::println);
    }

在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值