详解spring事务属性(转)
Spring声明式事务让我们从复杂的事务处理中得到解脱。使得我们再也无需要去处理获得连接、关闭连接、事务提交和回滚等这些操作。再也无需要我们在与事务相关的方法中处理大量的try…catch…finally代码。
我们在使用Spring声明式事务时,有一个非常重要的概念就是事务属性。事务属性通常由事务的传播行为,事务的隔离级别,事务的超时值和事务只读标志组成。我们在进行事务划分时,需要进行事务定义,也就是配置事务的属性。
Spring在TransactionDefinition接口中定义这些属性,以供PlatfromTransactionManager使用, PlatfromTransactionManager是spring事务管理的核心接口。
TransactionDefinitionpublic interface TransactionDefinition { int getPropagationBehavior(); int getIsolationLevel(); int getTimeout(); boolean isReadOnly();}isReadOnly(),事务是否只读,事务管理器能够根据这个返回值进行优化,确保事务是只读的。
Connection con1 = getConnection(); con.setAutoCommit(false); update employee set salary = 8000 where empId ="Mary";与此同时,Mary正在读取自己的工资
Connection con2 = getConnection();select salary from employee where empId ="Mary";con2.commit();Mary发现自己的工资变为了8000,欢天喜地!
con1.rollback();像这样,Mary记取的工资数8000是一个脏数据。
con1 = getConnection();select salary from employee empId ="Mary";在事务2中,这时财务人员修改了Mary的工资为2000,并提交了事务.
con2 = getConnection();update employee set salary = 2000;con2.commit();在事务1中,Mary 再次读取自己的工资时,工资变为了2000
select salary from employee empId ="Mary";
con1 = getConnection();Select * from employee where salary =1000;共读取10条记录
con2 = getConnection();Insert into employee(empId,salary) values("Lili",1000);con2.commit();事务1再次读取所有工资为1000的员工
select * from employee where salary =1000;
//事务属性 PROPAGATION_REQUIRED methodA{ …… methodB(); …… } //事务属性 PROPAGATION_REQUIRED methodB{ …… }
main{ metodB();}相当于
Main{Connection con=null; rry{ con = getConnection(); con.setAutoCommit(false);//方法调用methodB();//提交事务con.commit();}Catch(RuntimeException ex){ //回滚事务 con.rollback(); }finally{ //释放资源 closeCon();}}Spring保证在methodB方法中所有的调用都获得到一个相同的连接。在调用methodB时,没有一个存在的事务,所以获得一个新的连接,开启了一个新的事务。
main{ Connection con = null; try{ con = getConnection(); methodA(); con.commit();}cathc(RuntimeException ex){ con.rollback();}finally{ closeCon();} }调用MethodA时,环境中没有事务,所以开启一个新的事务.
//事务属性 PROPAGATION_REQUIRED methodA(){ methodB();}//事务属性 PROPAGATION_SUPPORTS methodB(){ ……}单纯的调用methodB时,methodB方法是非事务的执行的。
//事务属性 PROPAGATION_REQUIRED methodA(){ methodB();}//事务属性 PROPAGATION_MANDATORY methodB(){ ……}当单独调用methodB时,因为当前没有一个活动的事务,则会抛出异常
//事务属性 PROPAGATION_REQUIRED methodA(){ doSomeThingA();methodB();doSomeThingB();}//事务属性 PROPAGATION_REQUIRES_NEW methodB(){ ……}当单独调用methodB时,相当于把methodb声明为REQUIRED。开启一个新的事务,事务地执行。
main(){ methodA();}情况有些大不一样.相当于下面的效果。
main(){ TransactionManager tm = null;try{ //获得一个JTA事务管理器 tm = getTransactionManager(); tm.begin();//开启一个新的事务 Transaction ts1 = tm.getTransaction(); doSomeThing(); tm.suspend();//挂起当前事务 try{ tm.begin();//重新开启第二个事务 Transaction ts2 = tm.getTransaction(); methodB(); ts2.commit();//提交第二个事务 } Catch(RunTimeException ex){ ts2.rollback();//回滚第二个事务 } finally{ //释放资源 } //methodB执行完后,复恢第一个事务 tm.resume(ts1);doSomeThingB(); ts1.commit();//提交第一个事务}catch(RunTimeException ex){ ts1.rollback();//回滚第一个事务}finally{ //释放资源}}在这里,我把ts1称为外层事务,ts2称为内层事务。从上面的代码可以看出,ts2与ts1是两个独立的事务,互不相干。Ts2是否成功并不依赖于ts1。如果methodA方法在调用methodB方法后的doSomeThingB方法失败了,而methodB方法所做的结果依然被提交。而除了methodB之外的其它代码导致的结果却被回滚了。
//事务属性 PROPAGATION_REQUIRED methodA(){ doSomeThingA();methodB();doSomeThingB();}//事务属性 PROPAGATION_NOT_SUPPORTED methodB(){ ……}当单独调用methodB时,不启用任何事务机制,非事务地执行。
main(){ TransactionManager tm = null;try{ //获得一个JTA事务管理器 tm = getTransactionManager(); tm.begin();//开启一个新的事务 Transaction ts1 = tm.getTransaction(); doSomeThing(); tm.suspend();//挂起当前事务 methodB(); //methodB执行完后,复恢第一个事务 tm.resume(ts1);doSomeThingB(); ts1.commit();//提交第一个事务}catch(RunTimeException ex){ ts1.rollback();//回滚第一个事务}finally{ //释放资源}}
//事务属性 PROPAGATION_REQUIRED methodA(){ doSomeThingA();methodB();doSomeThingB();}//事务属性 PROPAGATION_NEVER methodB(){ ……}单独调用methodB,则非事务的执行。
//事务属性 PROPAGATION_REQUIRED methodA(){ doSomeThingA();methodB();doSomeThingB();}//事务属性 PROPAGATION_NESTEDmethodB(){ ……}如果单独调用methodB方法,则按REQUIRED属性执行。
main(){Connection con = null;Savepoint savepoint = null;try{ con = getConnection(); con.setAutoCommit(false); doSomeThingA(); savepoint = con2.setSavepoint(); try methodB(); }catch(RuntimeException ex){ con.rollback(savepoint); } finally{ //释放资源 } doSomeThingB(); con.commit();}catch(RuntimeException ex){ con.rollback();}finally{ //释放资源}}当methodB方法调用之前,调用setSavepoint方法,保存当前的状态到savepoint。如果methodB方法调用失败,则恢复到之前保存的状态。但是需要注意的是,这时的事务并没有进行提交,如果后续的代码(doSomeThingB()方法)调用失败,则回滚包括methodB方法的所有操作。