您的位置:首页 > 编程语言 > Java开发

Spring 事务在实际项目中遇到的问题

2017-03-12 00:00 239 查看
PROPAGATION_REQUIRED : 支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。

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

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

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

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

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

以上是Spring事务的传播行为,一般我们项目默认使用的是PROPAGATION_REQUIRED

如下图





1. 如果接口中方法需要语义化,那么可能会达不到基础项目默认配置的 声明式事务 申明的规则,从而没有被事务进行管理.

比如 : 购买XXX这个动作,buyXXX();如果声明式事务没有配置这项,那么需要自行加入配置

<tx:method name="buy*" propagation="REQUIRED"/>

否则事务没管理到,会出现一些数据不一致的问题.

如果觉得麻烦,那么可以声明式事务注解式一起使用,在方法上加入

@Transactional
@Override
public void buyXXX(){ }

注解即可

2. 事务传播行为的选择,根据业务场景选择不同的传播行为

这是我在一个计划任务处理时踩的坑

业务场景 :

每个月给用户赠送一定量的话费.

我的处理方式是 :

查询出当月所有需要赠送的记录,然后for循环调外部API进行赠送处理.

问题 :

1. 查询出当月所有需要赠送的记录(如果数据量日渐增大,那么一次全部查询出来,会造成java.lang.OutOfMemoryError)

2. 事务使用的是(PROPAGATION_REQUIRED默认事务),并且如果中间出现像SQL连接中断,数据库锁获取失败(有遇到过锁获取了40分钟还没有获取到,导致异常)等等,那么数据全部回滚.如果数据有1w条,中间已经处理了9999条,到最后一条数据处理失败了,数据回滚不说,任务还需要重来.

3. 调外部API进行赠送处理,外部只给了你充值的功能,并不会给你扣款,或者冲正的接口,如果中间出异常数据回滚了,那么只会回滚当前系统数据库的数据.

我后面修改了下代码

1. 查询时进行分页处理,处理时一页一页的处理.

2. 事务行为采用(PROPAGATION_REQUIRES_NEW,新建事务,如果当前存在事务,把当前事务挂起。)这样我处理一批(比如我设置粒度为10),就提交事务,这样,中间如果有异常,我最多损失10条数据,这10条数据再根据LOG进行处理. 当然这样频繁开启和提交事务,可能性能不太好.

还遇到过两个系统,但是数据源一样时,事务出现的问题

A系统保存了一个订单,订单号1001,然后把订单号1001传递给B系统,A系统等待B系统处理完返回结果,B系统会根据订单号1001去数据库查询,这个时候A系统是还没有提交事务的,那么B系统是查询不出来的,业务就走不下去了.

我之前的解决方法是 : A系统把保存了订单写一个单独的方法,事务行为是(PROPAGATION_REQUIRES_NEW),这样一旦保存后就立马提交到数据库了,B系统查询时就可以查询到记录了.(当然如果是分布式事务的话,就没有这个问题,只是当时什么构架,就这么处理了)

在实际项目中,可能还有很多关于事务传播行为不正确使用造成的问题,我们应该根据具体情况而使用不同的事务传播行为,而不是一概的使用PROPAGATION_REQUIRED.

遇到了几个事务坑后,让我更加重视在处理业务时事务行为的选择和搭配.

Spring 事务传播行为更详细的介绍

http://spring.cndocs.tk/transaction.html

http://blog.csdn.net/it_wangxiangpan/article/details/24180085
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: