Java数据库连接(Java Database Connectivity)是用来规范客户端如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法。通过JDBC,可以使用Java通过数据库驱动连接到数据库,编写SQL语句进行操作。

JDBC实现了开放式数据库连接(Open Database Connectivity)标准——一种早期使用C语言实现的数据库连接标准。ODBC提供了一套用来访问数据库的标准API,同时提供了驱动管理器,当数据库驱动注册到驱动管理器后,能够通过该驱动连接特定的数据库,对数据库进行访问。而JDBC就是Java版本的ODBC。

数据库驱动主要由数据库的提供者开发。对于JDBC,不同的数据库驱动能够操作相对应的数据库。JDBC的驱动类型主要分为以下4种:

  • JDBC-ODBC桥:此类驱动程序将JDBC调用转换成ODBC调用 , 然后使用ODBC与数据库进行通信。早期Java包含了驱动程序:sun.jdbc.odbc.JdbcOdbcDriver,但使用之前需要对ODBC数据源进行配置。JDK1.8不再提供JDBC/ODBC桥的支持。
  • 本地API驱动:用来和数据库的客户端API进行通信。使用前,需要安装Java类库和一些平台相关的代码(特定的驱动程序,类似ODBC)。通过驱动程序的转换,把Java程序中使用的JDBC API转换成NativeAPI,进而存取数据库。
  • 网络协议驱动:使用与具体数据库无关的协议,将数据库请求发送给服务器中间件。服务器再将数据库请求翻译成符合数据库规范的调用,再把这种调用传给数据库服务器。执行效率受网络带宽的影响。
  • 本地协议驱动:将JDBC请求直接转换成符合相关数据库系统规范的请求,可以直接和数据库通信。这种类型的驱动完全由Java实现,因此实现了平台独立性。执行效率相对于其他三种类型,不需要将jdbc调用转换成odbc/本地数据库接口/中间层服务器,效率高。最常用的驱动方式。

    连接步骤

    ```java
  1. 注册驱动
  2. 获取连接对象
  3. 获取Statement对象
  4. 执行SQL语句
  5. 处理查询结果集
  6. 关闭连接 ```

    注册驱动

    因为JDBC就是Java版本的ODBC,和ODBC一样,也需要将数据库驱动注册到驱动管理器后才能和数据库进行通信
  • java.sql.Driver是JDBC中提供的驱动接口,每一种数据库的驱动类都要实现这个接口。
    • 对于Oracle,驱动可以使用oracle.jdbc.driver.OracleDriver或oracle.jdbc.OracleDriver,前者是后者的子类。它们都是java.sql.Driver的实现类。
  • 在底层,当加载了一个驱动类后便能够将驱动注册到驱动管理器中。
  • 加载驱动类的方法包括:创建驱动对象、Class.forName(驱动类全类名)、设置环境变量,共三种方法。 ```java DriverManager.registerDriver( new oracle.jdbc.driver.OracleDriver()); // 在启动管理器注册驱动对象 new oracle.jdbc.driver.OracleDriver(); // 当驱动对象创建时也会自动注册

Class.forName(“oracle.jdbc.driver.OracleDriver”); // 使用反射可以加载驱动类,从而注册驱动对象,最推荐

System.setProperty(“jdbc.drivers”, “oracle.jdbc.driver.OracleDriver”); // 设置System环境变量,将jdbc.drivers的值设置为驱动类的全类名

  1. <a name="GM2dn"></a>
  2. ### 获取连接对象
  3. java.sql.DriverManager是JDBC的驱动管理器,注册驱动后,可通过它获取到数据库连接对象。
  4. - 告诉驱动管理器要连接到哪个数据库,管理器就会使用该数据库的驱动,并返回一个连接对象。该操作通过DriverManager.getConnection(url,user,password)方法实现。
  5. - 要连接的数据库通过url确定,并通过用户名和密码连接到数据库。
  6. ```java
  7. String url = "jdbc:oracle:thin:@localhost:1521:XE";
  8. // 格式:jdbc/odbc:数据库厂商:连接方式(thin/fat):@ip:端口:数据库名
  9. String user = "jy"; // 用户名
  10. String password = "jy"; // 密码
  11. Connection connection = DriverManager.getConnection(url, user, password);
  12. Properties properties = new Properties(); // 也可以使用Properties对象
  13. properties.setProperty("user", "jy");
  14. properties.setProperty("password", "jy");
  15. Connection connection = DriverManager.getConnection(url, properties);

执行SQL语句并处理

通过连接对象,可以向数据库传输SQL语句,对数据库进行操作。如果是查询操作,还会返回一个查询结果。

  • SQL语句使用Statement进行包装。使用connection.createStatement()方法获取SQL语句对象。语句对象可以执行一条SQL,也可以批量执行。
  • 返回的查询结果使用java.sql.ResultSet进行包装。ResultSet的数据按数据类型和字段进行存储,不同的数据类型可以使用不同的方法获取。使用迭代器获取每一行的数据。
  • 获取结果集时,列索引从1开始;列名为查询时指定的列名(别名)。 ```java Statement statement = connection.createStatement(); String sql = “create table “
    • “kk(id number primary key,”
    • “name varchar2(50))”; // 这里的SQL语句不能有分号 statement.execute(sql); // 执行SQL,返回一个boolean,表示有没有查询结果 statement.executeUpdate(sql); // 执行SQL,获取影响的行数,查询不影响行数

ResultSet result = statement.executeQuery(sql); // 执行SQL,获取查询结果集 while (set.next()) { // 有下一个记录时 long id = set.getLong(1); // 获取第1列,是Long类型的 String name = set.getString(2); // 获取第2列,是String类型的 long id2 = set.getLong(“id”); // 获取Long类型的id列 String name2 = set.getString(“name”); // 获取String类型的name列 System.out.println(id + “: “ + name); }

String sql2 = “delete from kk where id = 1”; String sql3 = “update kk set name = ‘12222’ where id = 2”; statement.addBatch(sql); // 添加语句 statement.addBatch(sql2); statement.addBatch(sql3); int[] is = statement.executeBatch(); // 批量执行SQL语句,返回的数组表示每条SQL影响的行数

  1. <a name="SY2Te"></a>
  2. ### 关闭连接
  3. 数据库操作完毕后,使用close()方法关闭ResultSet、Statement和Connection连接,释放资源。
  4. <a name="ynBw5"></a>
  5. ## 注意事项
  6. <a name="1315r"></a>
  7. ### 配置文件
  8. 在前两个步骤中,因为不同的应用程序要连接的数据库是不一样的,故需要指定不同的驱动,设置不同的url、用户名和密码。这就需要对该步骤进行封装,并从外部文件获取数据库配置。这也是为什么推荐使用反射的forName()方法来注册驱动的原因。数据库配置可以从[Properties](https://www.yuque.com/linja2020/saise0/qz71q7)配置文件中读取。<br />在对项目进行打包后,配置文件的路径可以从类加载路径获取。当配置文件放在src目录下时,配置文件的路径就是类加载器的根路径:
  9. ```java
  10. InputStream is = Test.class.getClassLoader().getResourceAsStream("datasource.properties");
  11. properties.load(is);

Statement

除了普通的SQL语句接口Statement,该接口还有两个子接口:PreparedStatement和CallableStatement。其中后者又是前者的子接口。
PreparedStatement(简称PS)是预处理的SQL语句接口,它具有以下特殊功能:

  • 预处理:能够对SQL进行预处理,在处理过程中将语句传递给数据库进行验证,避免错误的SQL。同时可以在此过程中对SQL语句进行检查,避免SQL语句注入等安全问题。
  • 占位符:PS具有占位符功能,对SQL检查完毕后,此后的数据只需填补占位符(?)即可,不用发送完整的SQL语句,避免连接字符串。对于大量重构的SQL语句(即结构相同数据不同的语句),速度更快。注意,表名等元数据不能使用占位符,只有数据可以。
  • 批处理:PS只能批处理同构的SQL语句。
    1. String sql = "insert into t_user(id, name, age) "
    2. + "values(user_seq.nextval, ?, ?)";
    3. PreparedStatement ps = conn.prepareStatement(sql);
    4. for (int i = 1; i <= 10000; i++) {
    5. ps.setString(1, "tom" + i); // 1是占位符序号,后面的是数据
    6. ps.setInt(2, 20);
    7. ps.executeUpdate(); // 执行
    8. // ps.addBatch(); 添加到批处理
    9. }
    10. // ps.executeBatch(); 执行批处理
    CallableStatement能够调用数据库中的存储过程。

    事务处理

    JDBC默认自动提交事务,但这样破坏了事务的原子性。可以改为手动提交。也可以回滚和设置记录点。
    1. connection.setAutoCommit(false); // 设置不自动提交事务
    2. connection.commit(); // 提交一次事务
    3. connection.rollback(); // 回滚事务
    4. Savepoint savepointC = connection.setSavepoint("c"); // 设置记录点
    5. connection.rollback(savepointC); // 回滚到记录点