事务

两种配置事务的方式

1.非注解式事务配置

2. 注解式事务配置
 
非注解式事务配置
<!-- 基本数据源配置  -->
<bean id="parentDataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="maxWait" value="3000"/>
<property name="validationQuery" value="SELECT 1"/>
<property name="testOnBorrow" value="false"/>
<property name="testWhileIdle" value="true"/>
<property name="initialSize" value="100"/>
<property name="maxActive" value="200"/>
<property name="minIdle" value="10"/>
<property name="maxIdle" value="50"/>
<property name="removeAbandoned" value="true"/>
<property name="removeAbandonedTimeout" value="30"/>
<property name="timeBetweenEvictionRunsMillis" value="30000"/>
<property name="driverClassName" value="${feima.jdbc.driver}"/>
</bean>

<bean id="feimaDataSource" parent="parentDataSource">
<property name="url" value="${feima.wr.jdbc.url}"/>
<property name="username" value="${feima.wr.jdbc.username}"/>
<property name="password" value="${feima.wr.jdbc.password}"/>
</bean>

<!-- 配置事务管理器 1.使用dataSourceManager 2.指定dataSource -->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="feimaDataSource"/>
</bean>
<!--xml 配置-->
<!--配置事务传播特性 1.指明使用哪个事务管理器 2.方法通配符配置传播特性-->
<tx:advice id="transactionInterceptor" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="query*" propagation="SUPPORTS"/>
<tx:method name="get*" propagation="SUPPORTS"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="deal*" propagation="REQUIRED"/>
<tx:method name="*" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>

<!--配置事务拦截器 1.通配符配置拦截哪些类、哪些方法、哪些返回值、哪些参数 2.指定切入点及通知 -->
<aop:config>
<aop:pointcut id="transactionPointCut" expression="execution(* com.jd.feima.crm.client.impl.remote.*.*(..))"></aop:pointcut>
<aop:advisor advice-ref="transactionInterceptor" pointcut-ref="transactionPointCut"/>
</aop:config>

注解式事务配置
<!-- 注解式事务 启用注解事务 -->
<tx:annotation-driven transaction-manager="transactionManager"/>


事务详解
事务传播特性:

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_SUPPORTS--支持当前事务,如果当前没有事务,就以非事务方式执行。

PROPAGATION_MANDATORY--支持当前事务,如果当前没有事务,就抛出异常。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NOT_SUPPORTED--以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。

PROPAGATION_NEVER--以非事务方式执行,如果当前存在事务,则抛出异常。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

备注:
可能大家还是对其中几个有点混淆,还是补充说明一下:
PROPAGATION_NESTED: 嵌套事务类型,是相对上面提到的六种情况(上面的六种应该称为平面事务类型),打个比方我现在有一个事务主要有一下几部分:
      1,从A用户帐户里面减去100元钱
      2,往B用户帐户里面添加100元钱
       这样看和以前不同的事务可能没有什么区别,那我现在有点特殊的要求就是,A用户有3个帐户,B用户有2个帐户,现在我的要求就是只要再A用户的3个帐户里面任意一个减去100元,往B用户的两个帐户中任意一个里面增加100元就可以了!
       一旦你有这样的要求那嵌套事务类型就非常适合你!我们可以这样理解,
       一:将“从A用户帐户里面减去100元钱” 和 “往B用户帐户里面增加100元钱”我们暂时认为是一级事务操作
       二:将从A用户的3个帐户的任意一个帐户里面减钱看做是“从A用户帐户里面减去100元钱”这个一级事务的子事务(二级事务),同样把后面存钱的看成是另一个的二级事务。
      问题一:当二级事务失败被rollback一级事务会不会被rollback?
      答案:如果二级事务被trycatch , 一级事务是不会被rollback的
      问题二:什么时候这个一级事务会commit,什么时候会被rollback呢?
      我们主要看二级里面出现的情况,当所有的二级事务被commit了并且一级事务没有失败的操作,那整个事务就算是一个成功的事务,这种情况整个事务会被commit。
当任意一个二级事务没有被commit, 且在一级事务里没有被try catch,那整个事务就是失败的,整个事务会被roolback。
还是拿上面的例子来说明吧!如果我在a的三个帐户里面减钱的操作都被二级事务给rollback了,也就是3个帐户里面都没有减钱成功,整个事务就失败了就会被rollback。如果A用户帐户三个帐户里面有一个可以扣钱而且B用户的两个帐户里面也有一个帐户可以增加钱,那整个事务就算成功的,会被 commit。
 
比较

PROPAGATION_REQUIRED--支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

PROPAGATION_REQUIRES_NEW--新建事务,如果当前存在事务,把当前事务挂起。

PROPAGATION_NESTED--如果当前存在事务,则在嵌套事务内执行。如果当前没有事务,则进行与PROPAGATION_REQUIRED类似的操作。

 
  • ServiceA {
  • /**
  • * 事务属性配置为 PROPAGATION_REQUIRED
  • */
  • voidmethodA(){ 
    insertA(a) ;
  • try {
  • ServiceB.methodB();
  • } catch (SomeException) {
  • // 执行其他业务, 如 ServiceC.methodC();
  • }
  • }
  •  
    B异常了
if(A== required && B=required) {
    a插入成功
    b中异常之前的数据未回滚
    c执行
    //就是说B支持A的事务, B异常了,但A中trycatch了, 相当于事务commit
}else if(A== required && B=requiredNew) {
    a插入成功
    B回滚
    c执行
}else if(A== required && B=nested) {
    a成功
    b回滚
    c.执行
}
 
  • A异常了
if(A== required && B=required) {
   全部回滚
}else if(A== required && B=requiredNew) {
    a回滚
    B成功
    c回滚
}else if(A== required && B=nested) {
    全部回滚
 
}
原文地址:https://www.cnblogs.com/chenge-0401/p/9520483.html