2.事务嵌套

2.1对于事务的传播级别为requiredNew,也就是被嵌套这要开启一个新的事务的话这个jdbc本身就支持

Connection connection = ds.getConnection();

connection.setAutoCommit(false);

PreparedStatement ps = connection.prepareStatement("insert into business_action(tx_id, name, state,gmt_create, gmt_modified) values (?,?,?,now(),now())");

            ps.setString(1, "tx-outer");

            ps.setString(2, "outertest");

            ps.setString(3, "I");

            ps.executeUpdate();

//开启嵌套事务

Connection connection2 = ds.getConnection();

connection2.setAutoCommit(false);

PreparedStatement ps2 =connection2.prepareStatement("insert intobusiness_action(tx_id, name, state, gmt_create, gmt_modified) values (?,?,?,now(),now())");

            ps2.setString(1, "tx-inner");

            ps2.setString(2, "inner");

            ps2.setString(3, "I");

            ps2.executeUpdate();

            System.out.println("xxxx");

//内层事务提交

connection2.commit();

connection.commit();

 

2.1对于事务的传播级别为required级别,也就是外层应经开始了事务就复用,没有开启那么开启一个事务, 这种场景还是有点小麻烦的

1)如何判断外层有无事务开启

2) 最外层的事务会做真正的提交或者回滚操作, 那么如何判断当前事务是不是最外层事务

3) 如果最外层自己业务正常,那么如何判断嵌套业务是否正常是否需要回滚

下面来看个简单的代码示例来解决上面那些问题

public class JdbcNestTransactionUtil {

    private static ThreadLocal<ConnecitonHolder>CONNECITON_HOLDER = new ThreadLocal<ConnecitonHolder>();

   

    public static Connection startTransaction(){

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

            try {

                holder = newConnecitonHolder(DatasourceUtil.getDataSource().getConnection());

                CONNECITON_HOLDER.set(holder);

            } catch (Exception e) {

                throw new RuntimeException(e);

            }

        } else {

            holder.count++;

        }

       

        try {

            holder.conn.setAutoCommit(false);

        } catch (SQLException e) {

            throw new RuntimeException(e);

        }

       

        return holder.conn;

    }

   

    public static void commitOrRollback() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

            throw new RuntimeException("数据库链接为空,无法commmitOrRollback");

        }

        if (holder.rollback) {

            rollback();

        } else {

            commit();

        }

    }

   

    private static void commit() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

            throw new RuntimeException("数据库链接为空,无法commmit");

        }

       

        if (holder.count == 0) {

            try {

                holder.conn.commit();

                holder.conn.close();

               

            } catch (SQLException e) {

                throw new RuntimeException(e);

            } finally {

                CONNECITON_HOLDER.remove();

            }

        } else {

            holder.count--;

        }

    }

   

    private static void rollback() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

            throw new RuntimeException("数据库链接为空,无法rollback");

        }

       

        if (holder.count == 0) {

            try {

                holder.conn.rollback();

                holder.conn.close();

            } catch (SQLException e) {

                throw new RuntimeException(e);

            } finally {

                CONNECITON_HOLDER.remove();

            }  

        } else {

            holder.count--;

        }

    }

   

    public static void setRollbackOnly() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

            throw new RuntimeException("数据库链接为空,无法commmit");

        }

       

        holder.rollback = true;

    }

   

    private static class ConnecitonHolder {

        private Connection conn;

        private int count;

        private boolean rollback;

       

        public ConnecitonHolder(Connectionconn) {

            this.conn = conn;

        }

    }

}

JdbcNestTransactionUtil工具类封装了事务操作,使得业务代码使用简单

1)    使用TheadLocal绑定事务,一个线程开启一个事务, 这样嵌套中的事物一旦当前线程开启了事务就不在再开启事物了

2)    利用一个int变量来保存事务的嵌套的深度,以此来判断出最外层

3)    rollback变量设置是否回滚, 无论那层业务异常,一旦设置true,最外层做真正回滚来保证整个业务的事物性

 

下面来看下如何使用

public void methodA() {

        Connection conn =JdbcNestTransactionUtil.startTransaction();

        try {

            数据库操作

        } catch (SQLException e) {

            JdbcNestTransactionUtil.setRollbackOnly();

        } finally {

            JdbcNestTransactionUtil.commitOrRollback();

        }

}

 

public void methodB() {

        Connection conn = JdbcNestTransactionUtil.startTransaction();

        try {

            数据库操作

        } catch (SQLException e) {

            JdbcNestTransactionUtil.setRollbackOnly();

        } finally {

            JdbcNestTransactionUtil.commitOrRollback();

        }

    }

 

methodA, methodB都是事务性操作,

testJdbcNestTx方法中开启了事务同时也调用的methodA,methodB方法是个嵌套事务示例。

public void testJdbcNestTx() {

        Connection conn =JdbcNestTransactionUtil.startTransaction();

        try {

            methodA();

            其他数据库操作

            methodB();

        } catch (SQLException e) {

            JdbcNestTransactionUtil.setRollbackOnly();

        } finally {

            JdbcNestTransactionUtil.commitOrRollback();

        }

}

上面只是简单示例,spring在jdbc事务之上做了层封装,支持更加复杂的数据操作,下面我们队spring的事务做个简单的介绍。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值