• 20【JDBC的事务处理】



    上一篇19【CallableStatement 接口】


    下一篇21【JDBC操作数据库元数据】

    目录【MySQL零基础系列教程】



    20【JDBC的事务处理】

    1.1 JDBC的事务处理

    之前我们是使用MySQL的命令来操作事务。接下来我们使用JDBC来操作银行转账的事务。

    • 数据准备:
    CREATE TABLE account (  
        id INT PRIMARY KEY AUTO_INCREMENT,  
        name VARCHAR(10),  
        money double  
    );  
    -- 添加数据  
    INSERT INTO account (name, money) VALUES ('a', 1000), ('b', 1000);
    
    select * from account;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    1.1.1 事务相关API

    • Connection中事务相关方法如下:
    方法名描述
    boolean getAutoCommit()获取本次连接是否自动提交事务,默认true
    void setAutoCommit(boolean autoCommit)设置本次连接是否自动提交事务
    void commit()提交事务
    void rollback()回滚事务
    int getTransactionIsolation()获取事务的隔离级别
    void setTransactionIsolation(int level)设置事务的隔离级别
    Savepoint setSavepoint()设置事务保存点
    void rollback(Savepoint savepoint)回滚到保存点

    1.1.2 案例测试

    1)模拟转账业务
    • 示例代码:
    package com.dfbz.demo;
    
    import com.dfbz.utils.JdbcUtils;
    import org.junit.Test;
    
    import java.sql.Connection;
    import java.sql.SQLException;
    import java.sql.Statement;
    
    /**
     * @author lscl
     * @version 1.0
     * @intro:
     */
    public class Demo15_事务 {
    
        /**
         * 模拟事务
         * @throws Exception
         */
        @Test
        public void test1() throws Exception{
            //创建连接对象
            Connection conn = null;
            Statement stmt = null;
            try {
                conn = JdbcUtils.getConnection();
    
                // 设置事务不要自动提交(手动提交,默认情况下,事务是自动提交的)
                conn.setAutoCommit(false);
    
                //创建语句对象
                stmt = conn.createStatement();
    
                //a扣钱
                stmt.executeUpdate("update account set money=money-500 where name='a'");
    
                // 模拟异常
    //            System.out.println(100 / 0);
    
                // b加钱
                stmt.executeUpdate("update account set money=money+500 where name='b'");
    
                // 提交事务
                conn.commit();
    
                System.out.println("转账成功");
            } catch (Exception e) {
    
                try {
                    // 回滚事务
                    conn.rollback();
                } catch (SQLException e1) {
                    e1.printStackTrace();
                }
    
                System.out.println("转账失败");
            } finally {
                JdbcUtils.close(conn, stmt);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    2)事务隔离级别

    Connection中有如下静态常量来规定隔离级别:

    • TRANSACTION_READ_UNCOMMITTED(1):读未提交
    • TRANSACTION_READ_COMMITTED(2):读已提交
    • TRANSACTION_REPEATABLE_READ(4):可重复读
    • TRANSACTION_SERIALIZABLE(8):串行化

    测试代码:

    /**
     * 测试隔离级别
     *
     * @throws Exception
     */
    @Test
    public void test2() throws Exception {
        Connection conn = JdbcUtils.getConnection();
    
        //创建语句对象
        Statement stmt = conn.createStatement();
    
            /*
                TRANSACTION_READ_UNCOMMITTED(1): 读未提交
                TRANSACTION_READ_COMMITTED(2): 读已提交
                TRANSACTION_REPEATABLE_READ(4): 可重复读
                TRANSACTION_SERIALIZABLE(8): 串行化
             */
    
        // 将本次连接的隔离级别设置为读未提交
        conn.setTransactionIsolation(Connection.TRANSACTION_READ_UNCOMMITTED);
    
        /*
         先在其他窗口创建一个事务修改数据但不提交,
         然后再断点执行下面代码,
         看下是否能查询到其他事务没提交的数据
         */
        ResultSet rs = stmt.executeQuery("select * from account");
    
        while (rs.next()) {
    
            String name = rs.getString("name");
            double money = rs.getDouble("money");
    
            System.out.println("name: " + name);
            System.out.println("money: " + money);
        }
    
        JdbcUtils.close(conn, stmt);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    3)事务回滚
    • 测试代码:
    /**
     * 测试回滚点
     *
     * @throws Exception
     */
    @Test
    public void test3() throws Exception {
        Connection conn = JdbcUtils.getConnection();
    
        // 设置手动提交事务
        conn.setAutoCommit(false);
    
        //创建语句对象
        Statement stmt = conn.createStatement();
    
        stmt.executeUpdate("update account set money=900;");
    
        // 设置保存点
        Savepoint p1 = conn.setSavepoint();
    
        stmt.executeUpdate("update account set money=800;");
    
        // 设置保存点
        Savepoint p2 = conn.setSavepoint();
    
        stmt.executeUpdate("update account set money=700;");
    
        // 回滚到p1保存点
        conn.rollback(p1);
    
        // 提交事务
        conn.commit();
    
        JdbcUtils.close(conn, stmt);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

  • 相关阅读:
    RabbitMQ:安装与部署
    Java网络通信
    4.jvm入门到精通
    什么是nacos/cas/fastdfs
    哈夫曼树的递归打印不能实现
    idea中maven项目打包成jar,报错没有主清单属性解决方法
    10.4 小任务
    Real closed field
    LeetCode 每日一题 2024/4/15-2024/4/21
    julia 笔记:复合类型 struct
  • 原文地址:https://blog.csdn.net/Bb15070047748/article/details/126570082