目录
事务是由一步或几步数据库操作序列组成的逻辑执行单元,这些序列要么都执行,要么都不执行
事务的四个特性:
事务处理过程的三个概念:
事务操作的具体步骤:
注意:
Connection接口在默认情况下会自动提交,即事务是关闭的,即一条SQL语句执行成功后,系统会立即调用commit()方法提交到数据库,而无法对其进行rollback回滚操作
通过调用Connection对象的setAutoCommit(boolean bool)方法可以开启或者关闭自动提交模式
代码:
- // 开启事务(关闭自动提交)
- con.setAutoCommit(false);
-
- // 提交事务
- con.commit();
-
- // 回滚事务
- con.rollback();
实例演示:
-
- import java.sql.*;
-
- public class EventManagementDemo {
-
- // JDBC控制事务
- // 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
-
- private static String driver = "com.mysql.cj.jdbc.Driver";
- private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
- private static String user = "root";
- private static String password = "root";
-
- public static void main(String[] args) {
- Connection connection = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- int count = 0;
- try {
- connection = DriverManager.getConnection(url,user,password); // 获取数据库连接对象
- String sql = "UPDATE tb_student SET studentName=? WHERE studentNo=?";
- pstmt = connection.prepareStatement(sql);
- pstmt.setString(1, "张三");
- pstmt.setInt(2,2013110101);
-
- // ------开启事务------- // 同时成功/同时失败
- connection.setAutoCommit(false);// 在执行sql语句之前开启事务
-
- count = pstmt.executeUpdate();
- System.out.println("更新" + count + "条记录");
- String sql_select = "SELECT * FROM tb_student";
- pstmt = connection.prepareStatement(sql_select);
- rs = pstmt.executeQuery();
- while(rs.next()){
- int no = rs.getInt(1);
- String name = rs.getString(2);
- System.out.println(no+"\t"+name);
- }
-
- int exception = 5/0; // 手动制造异常
- /*
- 通过实验可以得知:
- 在程序出错的情况下:
- 如果不开启事务管理,程序在执行到错误到错误代码片段时,
- 执行sqi语句的对象依然可以对数据库的数据进行修改,
- 反之,如果开启事务管理,
- 执行到错误代码片段时,执行sql语句的对象无法对数据库里面的数据进行操作
- */
-
- // ------提交事务-------
- connection.commit(); // 当所有sql语句都执行完提交事务
-
- } catch (SQLException e) {
-
- // ------回滚事务-------
- try {
- connection.rollback(); // 在catch中回滚事务
- } catch (SQLException ex) {
- ex.printStackTrace();
- }
- e.printStackTrace();
- }
- finally {
- if (rs != null){
- try {
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (pstmt != null){
- try {
- pstmt.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (connection != null){
- try {
- connection.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- }
-
- }
-
- }
根据结果集返回的数据可知,JDBC似乎成功修改了数据库中数据表的信息,但由于开启了事务管理,所以出现事务中断时,JDBC对数据库的修改并未起作用,而是恢复到了执行前的状态
执行SQL语句后的数据表:
JDBC通过保存点,可以更好地控制事物回滚
原数据表:
- import java.sql.*;
-
- public class SavePointDemo {
-
- // JDBC还支持保存点操作,通过保存点,可以更好的控制事务回滚
- // 保存点是事务中的逻辑回滚点
- // 设置保存点时,只要在保存点之后发生错误,就可以使用该rollback()方法撤消在保存点之前所做的事件。
-
- private static String driver = "com.mysql.cj.jdbc.Driver";
- private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
- private static String user = "root";
- private static String password = "root";
-
- public static void main(String[] args) {
- Connection connection = null;
- Savepoint savepoint = null;
- PreparedStatement pstmt = null;
- ResultSet rs = null;
- try {
- Class.forName(driver);
- connection = DriverManager.getConnection(url,user,password); // 获取数据库连接对象
- // -------开启事务-------
- connection.setAutoCommit(false);
- String sql1 = "INSERT INTO tb_student VALUES(2014310103,'张三','男','2022-7-5','北京','汉',null)";
- pstmt = connection.prepareStatement(sql1);
- pstmt.executeUpdate();
-
- // 设置保存点
- savepoint = connection.setSavepoint();
- String sql2 = "INSERT INTO tb_student VALUES(2014310104,'李四','女','2022-7-6','上海','满',null )";
- pstmt = connection.prepareStatement(sql2);
- pstmt.executeUpdate();
-
- // 回滚保存点
- connection.rollback(savepoint);
-
- // ------提交事务-------
- connection.commit(); // 当所有sql语句都执行完提交事务
-
- // -----恢复原有事务提交状态------
- connection.setAutoCommit(true);
-
- } catch (SQLException | ClassNotFoundException e) {
- // ------回滚事务-------
- if(connection != null){
- try {
- connection.rollback(); // 在catch中回滚事务
- } catch (SQLException ex) {
- ex.printStackTrace();
- }
- e.printStackTrace();
- }
- }
- finally {
- if (rs != null){
- try {
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (pstmt != null){
- try {
- pstmt.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (connection != null){
- try {
- connection.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- }
-
- }
-
- }
上述代码首先声明了一个Savepoint对象,然后在执行第一条数据插入操作后调用setSavepoint()方法设置保存点,执行完第二条插入操作后,事物回滚到保存点
进行插入操作后的数据表显示,在保存点之前执行的插入操作成功,而保存点之后执行操作失效
批量更新:即多条SQL语句将作为一批操作被同时收集,并同时提交
批量更新需得到底层数据库的支持,通过调用DatabaseMetaData接口的supports()方法来查看底层数据库是否支持批量更新
批量更新的步骤:
原数据表:
- import java.sql.*;
-
- public class DatabaseMetaDataDemo{
-
- // JDBC提供了批量更新功能,多条SQL语句将被作为一批操作被同时收集、提交
- // 通过调用DatabaseMetaData的supports()来查看底层数据库是否支持批量更新
-
- private static String driver = "com.mysql.cj.jdbc.Driver";
- private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
- private static String user = "root";
- private static String password = "root";
-
- public static void main(String[] args) {
- Connection connection = null;
- Statement stmt = null;
- ResultSet rs = null;
- int count = 0;
- try {
- connection = DriverManager.getConnection(url, user, password); // 获取数据库连接对象
-
- // 1.创建一个statement对象
- stmt = connection.createStatement();
-
- // 2.使用statement对象的addBatch方法收集多条sql语句
- String sql1 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='狗蛋'";
- String sql2 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='王一敏'";
- String sql3 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='江山'";
- String sql4 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='李明'";
- stmt.addBatch(sql1);
- stmt.addBatch(sql2);
- stmt.addBatch(sql3);
- stmt.addBatch(sql4);
-
- // 3.调用statement对象的excuteBatch方法同时执行所有sql语句
- stmt.executeBatch();
-
- } catch (SQLException e) {
- e.printStackTrace();
- }
-
- if (rs != null) {
- try {
- rs.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (stmt != null) {
- try {
- stmt.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
- if (connection != null) {
- try {
- connection.close();
- } catch (SQLException e) {
- e.printStackTrace();
- }
- }
-
- }
- }