2.事务嵌套

来源:互联网 发布:如何用手机淘宝开网店 编辑:程序博客网 时间:2024/06/05 10:25

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) 如果最外层自己业务正常,那么如何判断嵌套业务是否正常是否需要回滚

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

publicclass JdbcNestTransactionUtil {

    privatestatic ThreadLocal<ConnecitonHolder>CONNECITON_HOLDER =new ThreadLocal<ConnecitonHolder>();

   

    publicstatic Connection startTransaction(){

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

            try {

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

                CONNECITON_HOLDER.set(holder);

            } catch (Exception e) {

                thrownew RuntimeException(e);

            }

        } else {

            holder.count++;

        }

       

        try {

            holder.conn.setAutoCommit(false);

        } catch (SQLException e) {

            thrownew RuntimeException(e);

        }

       

        return holder.conn;

    }

   

    publicstatic void commitOrRollback() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

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

        }

        if (holder.rollback) {

            rollback();

        } else {

            commit();

        }

    }

   

    privatestatic void commit() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

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

        }

       

        if (holder.count == 0) {

            try {

                holder.conn.commit();

                holder.conn.close();

               

            } catch (SQLException e) {

                thrownew RuntimeException(e);

            } finally {

                CONNECITON_HOLDER.remove();

            }

        } else {

            holder.count--;

        }

    }

   

    privatestatic void rollback() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

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

        }

       

        if (holder.count == 0) {

            try {

                holder.conn.rollback();

                holder.conn.close();

            } catch (SQLException e) {

                thrownew RuntimeException(e);

            } finally {

                CONNECITON_HOLDER.remove();

            }  

        } else {

            holder.count--;

        }

    }

   

    publicstatic void setRollbackOnly() {

        ConnecitonHolder holder = CONNECITON_HOLDER.get();

        if (null == holder) {

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

        }

       

        holder.rollback =true;

    }

   

    privatestatic class ConnecitonHolder {

        private Connectionconn;

        privateint count;

        privateboolean rollback;

       

        public ConnecitonHolder(Connectionconn) {

            this.conn = conn;

        }

    }

}

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

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

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

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

 

下面来看下如何使用

publicvoid methodA() {

        Connection conn =JdbcNestTransactionUtil.startTransaction();

        try {

            数据库操作

        } catch (SQLException e) {

            JdbcNestTransactionUtil.setRollbackOnly();

        } finally {

            JdbcNestTransactionUtil.commitOrRollback();

        }

}

 

publicvoid methodB() {

        Connection conn = JdbcNestTransactionUtil.startTransaction();

        try {

            数据库操作

        } catch (SQLException e) {

            JdbcNestTransactionUtil.setRollbackOnly();

        } finally {

            JdbcNestTransactionUtil.commitOrRollback();

        }

    }

 

methodA, methodB都是事务性操作,

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

publicvoid testJdbcNestTx() {

        Connection conn =JdbcNestTransactionUtil.startTransaction();

        try {

            methodA();

            其他数据库操作

            methodB();

        } catch (SQLException e) {

            JdbcNestTransactionUtil.setRollbackOnly();

        } finally {

            JdbcNestTransactionUtil.commitOrRollback();

        }

}

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

1 0
原创粉丝点击