事物管理对于企业应用是非常重要的,它能够保证每个操作都是靠得住的,要保证后台数据库的数据是完整的。比如程序需要分别向两张表中插入数据,第一条sql执行成功,但是第二条sql执行失败。这时候就需要将第一条sql回滚了,确保数据的完整性。
事物主要包括四个特性:
原子性(Atomicity):事务是一个原子操作,由一系列动作组成。事务的原子性确保动作要么全部完成,要么完全不起作用。
一致性(Consistency):一旦事务完成(不管成功还是失败),系统必须确保它所建模的业务处于一致的状态,而不会是部分完成部分失败。在现实中的数据不应该被破坏。
隔离性(Isolation):可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据损坏。
持久性(Durability):一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响,这样就能从任何系统崩溃中恢复过来。通常情况下,事务的结果被写到持久化存储器中。
一个原子交易要么全部完成要么全部失败,这就是事物的完整性。
本文主要讲解的是Spring的声明式事物。
声明式:主要使用TransactionProxyFactoryBean,围绕Poxy的动态代理,能够自动的提交和回滚事务。
Spring声明式是以代理的方式实现对事务的管理。我们在Controller中所使用的Service对象,其实是代理对象的实例,并不是我们所写的Service对象实例。
声明式事务最大的优点就是不需要在业务逻辑中处理事物,能够保证业务代码的纯净度。这也是高内聚,低耦合的思想体现。只需在配置文件中加上相应的配置即可。因为事务治理是一个范例的横切逻辑,恰是 AOP 的用武之地。
下面的配置即是声明式事物的配置,它会扫描包com.xfl下所有的包(可以包含多个子包比如com.xfl.common,com.xfl.admin.service)下所有以ServiceImpl结尾的Java文件的所有方法。其中以add,append,insert,save,update,modify,edit,delete,remove等开头的方法必须运行在事物中,以get,load,find,search开头的方法不会运行在事物中。
事务放在service层中,service中这个类的方法之间的调用,事务是什么样的?service层调用另外一个service层的类的方法,事务又是怎样的?service方法中事务是根据该service层中最开始方法的事务属性来的。
必须要注意的是在Service中,只有发生了运行时异常才会回滚,所以运行时异常建议不要在service中捕获(使用 try catch捕获),如果必须要捕获则需要在catch或者finally中重新抛出运行时异常
throw new RuntimeException();
只有这样,数据才能回滚。
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--设置事物级别-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="append*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="save*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="modify*" propagation="REQUIRED" />
<tx:method name="edit*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="remove*" propagation="REQUIRED" />
<tx:method name="repair" propagation="REQUIRED" />
<tx:method name="delAndRepair" propagation="REQUIRED" />
<tx:method name="execute*" propagation="REQUIRED" />
<tx:method name="payFail*" propagation="REQUIRED" />
<tx:method name="distributeRedPackage*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" />
<tx:method name="find*" propagation="SUPPORTS" />
<tx:method name="load*" propagation="SUPPORTS" />
<tx:method name="search*" propagation="SUPPORTS" />
<tx:method name="dataGrid*" propagation="SUPPORTS" />
<tx:method name="*" propagation="SUPPORTS" />
</tx:attributes>
</tx:advice>
<!-- 事物处理 -->
<aop:config>
<aop:pointcut id="businessService" expression="execution(* com.xfl..*ServiceImpl.*(..))"/>
<aop:advisor pointcut-ref="businessService" advice-ref="txAdvice"/>
</aop:config>
Spring定义的7中传播行为:
PROPAGATION_REQUIRED 表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务
PROPAGATION_SUPPORTS 表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行
PROPAGATION_MANDATORY 表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常
PROPAGATION_REQUIRED_NEW 表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NOT_SUPPORTED 表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager
PROPAGATION_NEVER 表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常
PROPAGATION_NESTED 表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与
PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务
参考资料:
http://www.mamicode.com/info-detail-1248286.html
http://blog.csdn.net/ocean1010/article/details/6745316