• Java程序设计——事务管理(JDBC编程)


    目录

    一、事务

    二、保存点

    三、批量更新


    一、事务

    事务是由一步或几步数据库操作序列组成的逻辑执行单元,这些序列要么都执行,要么都不执行

    事务的四个特性:

    • 原子性:事务是最小执行单位,具有不可再分的特性,事务中的操作要么都执行,要么都不执行
    • 一致性:事务执行前和执行后,数据库都处于一致性状态
    • 隔离性:各事务的执行互不干扰,任意一个事物的内部操作对其它事务都是隔离的
    • 持久性:事务一旦提交,对数据库所做的任何操作都永久地记录到存储器中

    事务处理过程的三个概念:

    • 事务提交:指成功执行事务,事务提交又分两种方式:显式提交(commit)和自动提交(正常执行完毕)
    • 事务中止:指未能成功完成事务,从而执行中断
    • 事务回滚:指对事务中止所造成的的变更需要进行撤销处理,数据库返回事务执行前的状态,事务回滚又分两种方式:显式方式(rollback)和自动回滚(系统错误或强行退出)

    事务操作的具体步骤:

    1. 开启事务
    2. 执行任意条DML语句
    3. 执行成功,则提交事务
    4. 执行失败,则回滚事务

    注意:

    Connection接口在默认情况下会自动提交,即事务是关闭的,即一条SQL语句执行成功后,系统会立即调用commit()方法提交到数据库,而无法对其进行rollback回滚操作

    通过调用Connection对象的setAutoCommit(boolean bool)方法可以开启或者关闭自动提交模式

    代码:

    1. // 开启事务(关闭自动提交)
    2. con.setAutoCommit(false);
    3. // 提交事务
    4. con.commit();
    5. // 回滚事务
    6. con.rollback();

    实例演示:

    1. import java.sql.*;
    2. public class EventManagementDemo {
    3. // JDBC控制事务
    4. // 事务:一个包含多个步骤的业务操作。如果这个业务操作被事务管理,则这多个步骤要么同时成功,要么同时失败。
    5. private static String driver = "com.mysql.cj.jdbc.Driver";
    6. private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
    7. private static String user = "root";
    8. private static String password = "root";
    9. public static void main(String[] args) {
    10. Connection connection = null;
    11. PreparedStatement pstmt = null;
    12. ResultSet rs = null;
    13. int count = 0;
    14. try {
    15. connection = DriverManager.getConnection(url,user,password); // 获取数据库连接对象
    16. String sql = "UPDATE tb_student SET studentName=? WHERE studentNo=?";
    17. pstmt = connection.prepareStatement(sql);
    18. pstmt.setString(1, "张三");
    19. pstmt.setInt(2,2013110101);
    20. // ------开启事务------- // 同时成功/同时失败
    21. connection.setAutoCommit(false);// 在执行sql语句之前开启事务
    22. count = pstmt.executeUpdate();
    23. System.out.println("更新" + count + "条记录");
    24. String sql_select = "SELECT * FROM tb_student";
    25. pstmt = connection.prepareStatement(sql_select);
    26. rs = pstmt.executeQuery();
    27. while(rs.next()){
    28. int no = rs.getInt(1);
    29. String name = rs.getString(2);
    30. System.out.println(no+"\t"+name);
    31. }
    32. int exception = 5/0; // 手动制造异常
    33. /*
    34. 通过实验可以得知:
    35. 在程序出错的情况下:
    36. 如果不开启事务管理,程序在执行到错误到错误代码片段时,
    37. 执行sqi语句的对象依然可以对数据库的数据进行修改,
    38. 反之,如果开启事务管理,
    39. 执行到错误代码片段时,执行sql语句的对象无法对数据库里面的数据进行操作
    40. */
    41. // ------提交事务-------
    42. connection.commit(); // 当所有sql语句都执行完提交事务
    43. } catch (SQLException e) {
    44. // ------回滚事务-------
    45. try {
    46. connection.rollback(); // 在catch中回滚事务
    47. } catch (SQLException ex) {
    48. ex.printStackTrace();
    49. }
    50. e.printStackTrace();
    51. }
    52. finally {
    53. if (rs != null){
    54. try {
    55. rs.close();
    56. } catch (SQLException e) {
    57. e.printStackTrace();
    58. }
    59. }
    60. if (pstmt != null){
    61. try {
    62. pstmt.close();
    63. } catch (SQLException e) {
    64. e.printStackTrace();
    65. }
    66. }
    67. if (connection != null){
    68. try {
    69. connection.close();
    70. } catch (SQLException e) {
    71. e.printStackTrace();
    72. }
    73. }
    74. }
    75. }
    76. }

    根据结果集返回的数据可知,JDBC似乎成功修改了数据库中数据表的信息,但由于开启了事务管理,所以出现事务中断时,JDBC对数据库的修改并未起作用,而是恢复到了执行前的状态

    执行SQL语句后的数据表:


    二、保存点

    JDBC通过保存点,可以更好地控制事物回滚

    原数据表:

    1. import java.sql.*;
    2. public class SavePointDemo {
    3. // JDBC还支持保存点操作,通过保存点,可以更好的控制事务回滚
    4. // 保存点是事务中的逻辑回滚点
    5. // 设置保存点时,只要在保存点之后发生错误,就可以使用该rollback()方法撤消在保存点之前所做的事件。
    6. private static String driver = "com.mysql.cj.jdbc.Driver";
    7. private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
    8. private static String user = "root";
    9. private static String password = "root";
    10. public static void main(String[] args) {
    11. Connection connection = null;
    12. Savepoint savepoint = null;
    13. PreparedStatement pstmt = null;
    14. ResultSet rs = null;
    15. try {
    16. Class.forName(driver);
    17. connection = DriverManager.getConnection(url,user,password); // 获取数据库连接对象
    18. // -------开启事务-------
    19. connection.setAutoCommit(false);
    20. String sql1 = "INSERT INTO tb_student VALUES(2014310103,'张三','男','2022-7-5','北京','汉',null)";
    21. pstmt = connection.prepareStatement(sql1);
    22. pstmt.executeUpdate();
    23. // 设置保存点
    24. savepoint = connection.setSavepoint();
    25. String sql2 = "INSERT INTO tb_student VALUES(2014310104,'李四','女','2022-7-6','上海','满',null )";
    26. pstmt = connection.prepareStatement(sql2);
    27. pstmt.executeUpdate();
    28. // 回滚保存点
    29. connection.rollback(savepoint);
    30. // ------提交事务-------
    31. connection.commit(); // 当所有sql语句都执行完提交事务
    32. // -----恢复原有事务提交状态------
    33. connection.setAutoCommit(true);
    34. } catch (SQLException | ClassNotFoundException e) {
    35. // ------回滚事务-------
    36. if(connection != null){
    37. try {
    38. connection.rollback(); // 在catch中回滚事务
    39. } catch (SQLException ex) {
    40. ex.printStackTrace();
    41. }
    42. e.printStackTrace();
    43. }
    44. }
    45. finally {
    46. if (rs != null){
    47. try {
    48. rs.close();
    49. } catch (SQLException e) {
    50. e.printStackTrace();
    51. }
    52. }
    53. if (pstmt != null){
    54. try {
    55. pstmt.close();
    56. } catch (SQLException e) {
    57. e.printStackTrace();
    58. }
    59. }
    60. if (connection != null){
    61. try {
    62. connection.close();
    63. } catch (SQLException e) {
    64. e.printStackTrace();
    65. }
    66. }
    67. }
    68. }
    69. }

    上述代码首先声明了一个Savepoint对象,然后在执行第一条数据插入操作后调用setSavepoint()方法设置保存点,执行完第二条插入操作后,事物回滚到保存点

    进行插入操作后的数据表显示,在保存点之前执行的插入操作成功,而保存点之后执行操作失效


    三、批量更新

    批量更新:即多条SQL语句将作为一批操作被同时收集,并同时提交

    批量更新需得到底层数据库的支持,通过调用DatabaseMetaData接口的supports()方法来查看底层数据库是否支持批量更新

    批量更新的步骤:

    1. 创建一个Statement对象
    2. 调用Statement对象的addBatch()方法收集多条SQL语句
    3. 调用Statement对象的execteBatch()或executeLargeBatch()方法同时执行所有的SQL语句

     

    原数据表:

    1. import java.sql.*;
    2. public class DatabaseMetaDataDemo{
    3. // JDBC提供了批量更新功能,多条SQL语句将被作为一批操作被同时收集、提交
    4. // 通过调用DatabaseMetaData的supports()来查看底层数据库是否支持批量更新
    5. private static String driver = "com.mysql.cj.jdbc.Driver";
    6. private static String url = "jdbc:mysql://localhost:3306/de?serverTimezone=UTC&useSSL=false";
    7. private static String user = "root";
    8. private static String password = "root";
    9. public static void main(String[] args) {
    10. Connection connection = null;
    11. Statement stmt = null;
    12. ResultSet rs = null;
    13. int count = 0;
    14. try {
    15. connection = DriverManager.getConnection(url, user, password); // 获取数据库连接对象
    16. // 1.创建一个statement对象
    17. stmt = connection.createStatement();
    18. // 2.使用statement对象的addBatch方法收集多条sql语句
    19. String sql1 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='狗蛋'";
    20. String sql2 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='王一敏'";
    21. String sql3 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='江山'";
    22. String sql4 = "UPDATE tb_student SET classNo='ABC123' WHERE studentName='李明'";
    23. stmt.addBatch(sql1);
    24. stmt.addBatch(sql2);
    25. stmt.addBatch(sql3);
    26. stmt.addBatch(sql4);
    27. // 3.调用statement对象的excuteBatch方法同时执行所有sql语句
    28. stmt.executeBatch();
    29. } catch (SQLException e) {
    30. e.printStackTrace();
    31. }
    32. if (rs != null) {
    33. try {
    34. rs.close();
    35. } catch (SQLException e) {
    36. e.printStackTrace();
    37. }
    38. }
    39. if (stmt != null) {
    40. try {
    41. stmt.close();
    42. } catch (SQLException e) {
    43. e.printStackTrace();
    44. }
    45. }
    46. if (connection != null) {
    47. try {
    48. connection.close();
    49. } catch (SQLException e) {
    50. e.printStackTrace();
    51. }
    52. }
    53. }
    54. }

     

  • 相关阅读:
    基于毫米波雷达的可行驶区域检测(Freespace)
    centos下的dd命令,实例讲解
    【三十】springboot项目上高并发解决示例
    提示工程(Prompt Engineering)指南(入门篇)
    使用结构体指针作为参数赋值传递时的注意点
    CSS3------CSS选择器
    【C++】vector
    【蓝桥杯选拔赛真题43】Scratch航天飞行 少儿编程scratch蓝桥杯选拔赛真题讲解
    Python基础语法(一)
    Git命令图解
  • 原文地址:https://blog.csdn.net/Mr_Morgans/article/details/125610711