JDBC学习笔记

本文介绍了JDBC的基本概念,包括如何注册驱动、获取连接、执行SQL语句等关键步骤,并详细解析了Statement、PreparedStatement和CallableStatement的区别及应用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我是通过易百教程JDBC获取连接对象源码分析进行JDBC的粗略学习了,主要是为了梳理知识脉络。现在总结如下。
http://objcoding.com/2017/07/03/JDBC/
JDBC是用来建立Java程序与数据库的连接的,Java规定了一系列的API,然后让各个类型的数据库公司去实现这些API,Java只负责通过API与数据库通信。数据库公司实现好的API打包成一个jar包,我们称之为数据库的驱动包。通过将该包导入到Java的库中,就可以使用对应的数据库了。数据库驱动有4种类型,上面说的方法就是第4种类型,也是最常用的类型。

0. 前言

由于是与数据库进行IO操作,因此后续步骤都应该在try/catch/finally块中操作,并对应捕获相应的SQLException。

try{
    //建立通信&使用数据库
}catch(){
    //捕获各种Exception
}finally{
    //完成通信的一系列关闭操作
}

1. JDBC驱动的注册

导入一个数据库驱动包后, 我们要在使用改数据库的时候进行注册。具体的方法就是利用反射来加载该类:

Class.forName("com.mysql.jdbc.Driver");
Connection conn = null;
conn = DriverManager.getConnection("jdbc:mysql://hostname:port/db_name","db_username", "db_password");
conn.close();

其具体的原理如下,是利用了Driver类中的静态代码块进行驱动的注册的。当加载这个类是就会自动运行静态代码块。

public class Driver extends NonRegisteringDriver implements java.sql.Driver {
  //静态代码块
  static {
    try {
      java.sql.DriverManager.registerDriver(new Driver());// 注册驱动
    } catch (SQLException E) {
      throw new RuntimeException("Can't register driver!");
    }
       }
}

2. 获取Connection接口实例

String URL = "jdbc:oracle:thin:@amrood:1521:EMP";
// String URL = "jdbc:oracle:thin:@192.0.0.10:1521:EMP";
String USER = "username";
String PASS = "password"
Connection conn = DriverManager.getConnection(URL, USER, PASS);

如上所示,在注册好驱动后,我们利用DriverManager.getConnection(URL, USER, PASS);这个静态方法获得一个Connection类,接着就是通过该类进行一系列的数据库通信操作。
URL的书写方式类似HTML语言,为“通信协议://主机地址/数据库名?参数1&参数2”.
注:Connection类要在使用完成后用.close()随时关闭,保证良好的代码习惯。

3. 获取Statement接口实例

通过对Connection实例conn操作,我们就可以获得对应的Statement实例。 具体的Statement实例有三种,

3.1. Statement对象

它通过无参方法con.creatStatement()返回得到。接着通过调用Statement的实例方法进行数据库的操作。具体的实例方法有三个:boolean(是否有返回集ResultSet) execute (String SQL),int(返回受影响的条目数) executeUpdate (String SQL),ResultSet executeQuery(String SQL)。这三个方法都接受一个String类参数sql,这个参数就是数据库命令语句的字符串形式。例子如下:

...
      System.out.println("Creating statement...");
      stmt = conn.createStatement();
      String sql = "UPDATE Employees set age=30 WHERE id=103";

      // Let us check if it returns a true Result Set or not.
      Boolean ret = stmt.execute(sql);
      System.out.println("Return value is : " + ret.toString() );

      // Let us update age of the record with ID = 103;
      int rows = stmt.executeUpdate(sql);
      System.out.println("Rows impacted : " + rows );

      // Let us select all the records and display them.
      sql = "SELECT id, first, last, age FROM Employees";
      ResultSet rs = stmt.executeQuery(sql);
...

3.2. PreparedStatement对象

PreparedStatement接口扩展了Statement接口,它添加了比Statement对象更好一些优点的功能。
此语句可以动态地提供/接受参数。
它通过有参方法con.prepareStatement(String sql)返回得到。即该对象需要事先准备好一个String的sql语句,该语句形式如下:String SQL = "Update Employees SET age = ? WHERE id = ?";
JDBC中的所有参数都由 ? 符号作为占位符,这被称为参数标记。 在执行SQL语句之前,必须为每个参数(占位符)提供值。
setXXX()方法将值绑定到参数,其中XXX表示要绑定到输入参数的值的Java数据类型。如stmt.setInt(1,10)表示age=10, 如果忘记提供绑定值,则将会抛出一个SQLException。
每个参数标记是它其顺序位置引用。第一个标记表示位置1,下一个位置2等等。 该方法与Java数组索引不同(它不从0开始)。
所有Statement对象与数据库交互的方法(a)execute(),(b)executeQuery()和(c)executeUpdate()也可以用于PreparedStatement对象。 但是,这些方法被修改为可以使用输入参数的SQL语句。
注:使用该对象可以防止SQL注入攻击,并且对于反复使用的SQL语句,该类能有更高的效率进行执行。

3.3. CallableStatement对象

该对象主要是用于调用数据库中的储存过程的。由于储存过程含有IN,OUT,INOUT对象,因此在用问号占位后,对于IN位置的变量,仍用setXXX()来设置,但是对于OUT位置的问号则要用一个额外的CallableStatement对象方法registerOutParameter()registerOutParameter()方法将JDBC数据类型绑定到存储过程并返回预期数据类型。用法如下:stmt.registerOutParameter(java.sql.Types.VARCHAR)

···
      System.out.println("Creating statement...");
      String sql = "{call getEmpName (?, ?)}";//SQL转义语法    
      stmt = conn.prepareCall(sql);

      //Bind IN parameter first, then bind OUT parameter
      int empID = 102;
      stmt.setInt(1, empID); // This would set ID as 102
      // Because second parameter is OUT so register it
      stmt.registerOutParameter(2, java.sql.Types.VARCHAR);

      //Use execute method to run stored procedure.
      System.out.println("Executing stored procedure..." );
      stmt.execute();

      //Retrieve employee name with getXXX method
      String empName = stmt.getString(2);//通过getXXX方式获得OUT参数。
      System.out.println("Emp Name with ID:" + 
      empID + " is " + empName);
···

4. ResultSet类的操作

java.sql.ResultSet接口表示数据库查询的结果集。

4.1. ResultSet的属性

在创建StatementPrepareStatement,CallableStatement时使用的对应方法时,我们可以通过给这些方法传入参数来设置ResultSet的属性是仅仅能向后遍历,还是前后都可以遍历。以及是否会在数据库更新后自动更新结果集。

4.2. ResultSet的使用

由于是返回的一个集合的迭代器,因此我们有以下操作:

  • 移动迭代器(光标)的操作
  • 读取当前光标所指的结果行的数据的操作
  • 更新当前行的数据的操作(仅仅是结果集,不会改变数据库内数据)
  • 更新当前行对应的数据库行的操作(会改变数据库内容

5. 事务操作

由于数据库读写是IO操作,因此为了保证原子性,我们需要采用一系列的事务操作。如提交,回滚,设置保存点。

5.1. 提交

con.commit()用于将自上一次提交后的所有改动操作真正的提交执行。

5.2. 回滚

con.rollback()用于将自上一次提交后的所有改动操作全部取消。时常将回滚操作放在catch块内进行。

5.3. 保存点

通过设置保存点位置,可以将操作回滚至保存点处,而不用全部回滚。如下:

try{
   //Assume a valid connection object conn
   conn.setAutoCommit(false);
   Statement stmt = conn.createStatement();

   //set a Savepoint
   Savepoint savepoint1 = conn.setSavepoint("Savepoint1");
   String SQL = "INSERT INTO Employees " +
                "VALUES (106, 24, 'Curry', 'Stephen')";
   stmt.executeUpdate(SQL);  
   //Submit a malformed SQL statement that breaks
   String SQL = "INSERTED IN Employees " +
                "VALUES (107, 32, 'Kobe', 'Bryant')";
   stmt.executeUpdate(SQL);
   // If there is no error, commit the changes.
   conn.commit();

}catch(SQLException se){
   // If there is any error.
   conn.rollback(savepoint1);
}

6. 批处理

对于statement类的执行,我们可以通过将各种statement类加入一个batch(批处理集合)中,然后执行这个batch来达到统一执行多条语句的效果。(注意要将自动提交false)
主要是使用stmt.addBatch()stmt.excuteBatch()来添加执行批处理。例子如下:

// Create SQL statement
String SQL = "INSERT INTO Employees (id, first, last, age) " +
             "VALUES(?, ?, ?, ?)";

// Create PrepareStatement object
PreparedStatemen pstmt = conn.prepareStatement(SQL);

//Set auto-commit to false
conn.setAutoCommit(false);

// Set the variables
pstmt.setInt( 1, 400 );
pstmt.setString( 2, "JDBC" );
pstmt.setString( 3, "Li" );
pstmt.setInt( 4, 33 );
// Add it to the batch
pstmt.addBatch();

// Set the variables
pstmt.setInt( 1, 401 );
pstmt.setString( 2, "CSharp" );
pstmt.setString( 3, "Liang" );
pstmt.setInt( 4, 31 );
// Add it to the batch
pstmt.addBatch();

//add more batches
.
.
.
.
//Create an int[] to hold returned values
int[] count = stmt.executeBatch();

//Explicitly commit statements to apply changes
conn.commit();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值