从零开始学JDBC--1.11 事务机制以及案例分析

事务的定义:

事务是指作为单个逻辑工作单元执行的一系列操作,要么完全地执行,要么完全地不执行。

事务的特性在这里就不详细介绍了,主要是原子性、一致性、隔离性、持久性(简称ACID)

java.sql.Connection类中关于事务的三个方法:

Connection.setAutoCommit(false); —开启事务
Connection.rollback(); —回滚事务
Connection.commit(); —提交事务

1.首先创建操作对象—账户表

在表中我们先给设定初始值:
张三:初始金额10000元
李四:初始金额1元

-- 账户表的创建
CREATE TABLE account(
 id INT PRIMARY KEY AUTO_INCREMENT,
 accountName VARCHAR(20),
 money DOUBLE
);
//--------定义类 以及其私有成员变量---------
public class AccountDao {

    private Connection conn;
    private PreparedStatement pstmt;

假设张三账户中初始余额为10000元,李四初始余额为1元。

1. 没有使用事务(张三向李四转账1000)



    @Test
    public void trans1(){

        String sql_zs = "update account set money=money-1000 where accountName='张三'";
        String sql_ls = "update account set money=money+1000 where accountName='李四'";
        try {
            //获取连接
            conn = JdbcUtil.getConnection();

            //------------第一次  张三-1000-----------------------
            pstmt = conn.prepareStatement(sql_zs);
            pstmt.executeUpdate();

            //------------第二次  李四+1000-----------------------
            pstmt = conn.prepareStatement(sql_ls);
            pstmt.executeUpdate();

        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtil.closeAll(conn, pstmt, null);
        }
    }

执行结果:
初始状态:

成功情况:两条SQL都成功执行,张三金额减少1000,李四金额增加1000

这里搞一点小破坏,模拟第二条sql出错,将第二条sql修改成如下情况:

String sql_ls = "update_ account set money=money+1000 where accountName='李四'";

重新执行,出现失败情况:第二条SQL执行出错,出现了张三的金额减少了1000,而李四的金额没变!! 这是绝不允许发生的情况!

因此接下来我们引入事务

2. 使用事务,当发生异常时全部回滚(张三向李四转账1000)

    @Test
    public void trans2(){

        String sql_zs = "update account set money=money-1000 where accountName='张三'";
        String sql_ls = "update account set money=money+1000 where accountName='李四'";
        try {
            //获取连接
            conn = JdbcUtil.getConnection();
            conn.setAutoCommit(false);  //开启事务,需手动进行提交
            //------------第一次  张三-1000-----------------------
            pstmt = conn.prepareStatement(sql_zs);
            pstmt.executeUpdate();

            //------------第二次  李四+1000-----------------------
            pstmt = conn.prepareStatement(sql_ls);
            pstmt.executeUpdate();

        } catch (Exception e) {
            try {
                conn.rollback();  //发生异常时,进行事务回滚操作
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally{
            try {
                conn.commit();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            JdbcUtil.closeAll(conn, pstmt, null);
        }
    }

执行结果:
初始状态:

成功的情况和上面例1一样:两条SQL都成功执行,张三金额减少1000,李四金额增加1000
这里主要讲一下失败情况:
由于事务的保护机制,即使发生SQL执行出错的情况,事务也能回滚到事务执行的起点,就相当于什么都没发生一样,因此结果会和初始状况一样:

3.使用事务,当发生异常时,回滚到SavePoint 。(张三向李四第一次转账1000,第二次转账500)

Connection还提供了一个功能,就是在发生异常时,回滚到自定义的SavePoint。
这种情况仅适用于在一个事务中执行多条SQL语句,并且确保SavePoint之前的SQL一定能执行成功。

    @Test
    public void trans3(){
        Savepoint sp = null;

        String sql_zs1 = "update account set money=money-1000 where accountName='张三'";
        String sql_ls1 = "update account set money=money+1000 where accountName='李四'";

        String sql_zs2 = "update account set money=money-500 where accountName='张三'";
        String sql_ls2 = "update- account set money=money+500 where accountName='李四'";
        try {
            //获取连接
            conn = JdbcUtil.getConnection();
            conn.setAutoCommit(false);  //开启事务,需手动进行提交
            //------------第一次  张三向李四转1000-----------------------
            pstmt = conn.prepareStatement(sql_zs);
            pstmt.executeUpdate();
            pstmt = conn.prepareStatement(sql_ls);
            pstmt.executeUpdate();

            sp = conn.setSavepoint(); //创建回滚点(切记,这样写要确保第一次转账肯定能执行成功!!!)

            //------------第二次  张三向李四转500-----------------------
            pstmt = conn.prepareStatement(sql_zs2);
            pstmt.executeUpdate();
            pstmt = conn.prepareStatement(sql_ls2);
            pstmt.executeUpdate();


        } catch (Exception e) {
            try {
                conn.rollback(sp);  //发生异常时,进行事务回滚操作
            } catch (SQLException e1) {
                e1.printStackTrace();
            }
            e.printStackTrace();
        }finally{
            try {
                conn.commit();
            } catch (SQLException e) {
                e.printStackTrace();
            }
            JdbcUtil.closeAll(conn, pstmt, null);
        }
    }
}

执行结果:
四条SQL都执行成功的情况:
张三向李四第一次转账1000,第二次转账500都执行成功:

张三向李四第一次转账1000成功,第二次转账500失败,由于SavePoint设定在第一次转账之后,第二次转账之前,所以当第二次转账发生异常时,事务机制将回滚到第一次转账完成,第二次转账还没开始的时候:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值