关于Spring事务的问题

场景:在业务开发中有一个方法,这个方法是无论异常还是失败都要让他执行成功,比如说数据库要有一个计数的功能,只要调用了这个方法就会去把数据库表字段加1;假如我们在其他service里面调用了这个方法,而且还是多线程高并发的情况下,这个方法就很容易出问题;这个方法的步骤为读取改值,并且修改加1。


1.在多线程的情况下,容易读取到相同的值,比如在读取该值的时候,还没有来得及加1,

2.在整个业务方法没有执行成功的时候,该值不会去加1,所以其他线程看到的全部都是第一次读取过来的值;

这个时候解决思路是,读取值和修改值的方法加上同步,让它变成原子操作;

这里第二个不好解决,就是关于spring的事务配置问题,先来看看我们项目的事务声明方式

	
   <bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
		<property name="dataSource" ref="dataSource"/>
		<property name="configLocation" value="classpath:owms-business/sqlMap-config.xml"/>
	</bean>

    <!--事务配置-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--方法后缀是WithTx加入事务-->
            <tx:method name="*WithTx" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
        </tx:attributes>
    </tx:advice>
    
    <aop:config>
        <aop:pointcut id="myPointCut" expression="execution(* com.business.manage.*.*.*.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointCut"/>
    </aop:config>

这里事务会在manage里面加上WithTx方法生效,如果我把某个manage方法不加上 WithTx然后这个时候在用ibatis的

<span style="white-space:pre">	</span>sqlMapClient.startTransaction(); //事务开始
 <span style="white-space:pre">	</span>方法写这里
        sqlMapClient.commitTransaction(); //提交事务,从开始到这里是一个事务
        sqlMapClient.endTransaction(); //事务结束

事务是不是就可以让这个方法不受spring管理而单独生效了,结果发现并不能,这里虽然没有加 WithTx后缀,但是他仍然受spring的AOP管理,这个时候他并没有释放出他的权利,所以你Ibatis的事务根本不起作用,那么怎么解决这个办法了,这里要用到

@Transactional中的propagation属性

在Spring的事务管理中,我们可以使用@Transactional这一annotation来对事务进行声明式的设定。具体而言,就是在类或者方法前添加@Transactional并传入属性参数以获取所需要的Transaction特性。Spring中的@Transactional有5个属性:Propagation、Isolation、Rollback Rules、Timeout和Read-Only,其中Propagation属性定义了Transaction的边界 — 是否使用Transaction、在Transaction已存在的情况下如何表现等。

Propagation属性

@Transactional中Propagation属性有7个选项可供选择:

  • Propagation.MANDATORY 。当前方法必须在已经定义的Transaction中运行,如果没有已定义的Transaction则抛出异常。
  • Propagation.NESTED 。如果没有已定义的Transaction,当前方法新开一个Transaction并在该Transaction中运行。如果存在已定义的Transaction,当前方法在嵌套事务(Nested Transaction)中运行 — 嵌套事务中可以定义储存点,因此可以独立于外部的Transaction而进行rollback。
  • Propagation.NEVER 。当前方法不应在Transaction中运行,如果存在已经定义的Transaction则抛出异常。
  • Propagation.NOT_SUPPORTED 。当前方法不应在Transaction中运行,如果存在已经定义的Transaction,则该Transaction暂停(挂起)直至该方法运行完毕。
  • Propagation.REQUIRED 。 默认值 。当前方法必须在Transaction中运行。如果存在已经定义的Transaction,则该方法在已定义的Transaction中运行;如果不存在已经定义的Transaction,则该方法新开一个Transaction并在其中运行。
  • Propagation.REQUIRES_NEW 。当前方法必须在新开的Transaction中运行。如果存在已经定义的Transaction,则该已定义的Transaction暂停直至新开的Transaction执行完毕。
  • Propagation.SUPPORTS 。当前方法不需要在Transaction中运行,但如果存在已经定义的Transaction,则该方法也可以在Transaction中正常执行。

Propagation属性实例

观察以下两个定义了@Transactional的方法,innerMethod()模拟了Transaction已经存在的情况,outMethod()则模拟了不存在已定义Transaction的情况:

@Transactional
public void outMethod() {
    exampleDAO.doSomething();
    innerMethod();
}

@Transactional
public void innerMethod() {
    exampleDAO.doElse();
}

对于这两个方法,定义不同的Propagation属性值所产生的效果如下(Propagation.NESTED的情况较为复杂,在此忽略): 

Propagation属性 outMethod innerMethod
Propagation.MANDATORY .抛出异常 .在outMethod的Transaction中运行
Propagation.NEVER .不在Transaction中运行 .抛出异常
Propagation.NOT_SUPPORTED .不在Transaction中运行 .outMethod的Transaction暂停直至innerMethod执行完毕
Propagation.REQUIRED ( 默认值 ) .新开一个Transaction并在其中运行 .在outMethod的Transaction中运行
Propagation.REQUIRES_NEW .新开一个Transaction并在其中运行 .outMethod的Transaction暂停直至innerMethod中新开的Transaction执行完毕
Propagation.SUPPORTS .不在Transaction中运行 .在outMethod的Transaction中运行
只要在该方法上加上@Transactional(propagation = Propagation.NOT_SUPPORTED),这样Spring就会把它对这个方法事务的管理权释放出去,然后我们就可以在里面使用Ibatis事务去进行管理了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值