关键词:
最近做项目写后台java代码,有人遇到了业务层的逻辑代码发生了错误,但是持久层的数据却没有回滚,这是非常不应该的,应为按照逻辑,发生异常,所有的数据就应该回滚,不然会产生非常多的脏数据。针对这个情况,产生这样的原因主要有以下几个方面的原因:
后台采用SpringBoot框架,一般都会引用spring-boot-starter
或者spring-boot-starter-web
,而这两个起步依赖中都已经包含了对于spring-boot-starter-jdbc
或spring-boot-starter-data-jpa
的依赖。 当我们使用了这两个依赖的时候,框架会自动默认分别注入DataSourceTransactionManager
或JpaTransactionManager
。 所以我们不需要任何额外配置就可以用@Transactional
注解进行事务的使用。
提示
@Transactional注解只能应用到public可见度的方法上,可以被应用于接口定义和接口方法,方法会覆盖类上面声明的事务。
例如用户新增需要插入用户表、用户与岗位关联表、用户与角色关联表,如果插入成功,那么一起成功,如果中间有一条出现异常,那么回滚之前的所有操作, 这样可以防止出现脏数据,就可以使用事务让它实现回退。
做法非常简单,我们只需要在方法或类添加@Transactional
注解即可。
@Transactional public int insertUser(User user) // 新增用户信息 int rows = userMapper.insertUser(user); // 新增用户岗位关联 insertUserPost(user); // 新增用户与角色管理 insertUserRole(user); return rows;
常见坑点1:遇到检查异常时,事务开启,也无法回滚。 例如下面这段代码,用户依旧增加成功,并没有因为后面遇到检查异常而回滚!!
@Transactional
public int insertUser(User user) throws Exception
// 新增用户信息
int rows = userMapper.insertUser(user);
// 新增用户岗位关联
insertUserPost(user);
// 新增用户与角色管理
insertUserRole(user);
// 模拟抛出SQLException异常
boolean flag = true;
if (flag)
throw new SQLException("发生异常了..");
return rows;
原因分析:因为Spring
的默认的事务规则是遇到运行异常(RuntimeException)
和程序错误(Error)
才会回滚。如果想针对检查异常进行事务回滚,可以在@Transactional
注解里使用 rollbackFor
属性明确指定异常。
例如下面这样,就可以正常回滚:
@Transactional(rollbackFor = Exception.class)
public int insertUser(User user) throws Exception
// 新增用户信息
int rows = userMapper.insertUser(user);
// 新增用户岗位关联
insertUserPost(user);
// 新增用户与角色管理
insertUserRole(user);
// 模拟抛出SQLException异常
boolean flag = true;
if (flag)
throw new SQLException("发生异常了..");
return rows;
常见坑点2: 在业务层捕捉异常后,发现事务不生效。 这是许多新手都会犯的一个错误,在业务层手工捕捉并处理了异常,你都把异常“吃”掉了,Spring
自然不知道这里有错,更不会主动去回滚数据。
例如:下面这段代码直接导致用户新增的事务回滚没有生效。
@Transactional
public int insertUser(User user) throws Exception
// 新增用户信息
int rows = userMapper.insertUser(user);
// 新增用户岗位关联
insertUserPost(user);
// 新增用户与角色管理
insertUserRole(user);
// 模拟抛出SQLException异常
boolean flag = true;
if (flag)
try
// 谨慎:尽量不要在业务层捕捉异常并处理
throw new SQLException("发生异常了..");
catch (Exception e)
e.printStackTrace();
return rows;
推荐做法:在业务层统一抛出异常,然后在控制层统一处理。
@Transactional
public int insertUser(User user) throws Exception
// 新增用户信息
int rows = userMapper.insertUser(user);
// 新增用户岗位关联
insertUserPost(user);
// 新增用户与角色管理
insertUserRole(user);
// 模拟抛出SQLException异常
boolean flag = true;
if (flag)
throw new RuntimeException("发生异常了..");
return rows;
Transactional
注解的常用属性表:
属性 | 说明 |
---|---|
propagation | 事务的传播行为,默认值为 REQUIRED。 |
isolation | 事务的隔离度,默认值采用 DEFAULT |
timeout | 事务的超时时间,默认值为-1,不超时。如果设置了超时时间(单位秒),那么如果超过该时间限制了但事务还没有完成,则自动回滚事务。 |
read-only | 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。 |
rollbackFor | 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。xxx1.class, xxx2.class,…… |
noRollbackFor | 抛出 no-rollback-for 指定的异常类型,不回滚事务。xxx1.class, xxx2.class,…… |
提示
事务的传播机制是指如果在开始当前事务之前,一个事务上下文已经存在,此时有若干选项可以指定一个事务性方法的执行行为。 即:在执行一个@Transactinal注解标注的方法时,开启了事务;当该方法还在执行中时,另一个人也触发了该方法;那么此时怎么算事务呢,这时就可以通过事务的传播机制来指定处理方式。
TransactionDefinition
传播行为的常量:
常量 | 含义 |
---|---|
TransactionDefinition.PROPAGATION_REQUIRED | 如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。这是默认值。 |
TransactionDefinition.PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 |
TransactionDefinition.PROPAGATION_SUPPORTS | 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 |
TransactionDefinition.PROPAGATION_NOT_SUPPORTED | 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 |
TransactionDefinition.PROPAGATION_NEVER | 以非事务方式运行,如果当前存在事务,则抛出异常。 |
TransactionDefinition.PROPAGATION_MANDATORY | 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。 |
TransactionDefinition.PROPAGATION_NESTED | 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于TransactionDefinition.PROPAGATION_REQUIRED。 |
如有不足,敬请指出
jpa中事务回滚的问题(代码片段)
...封装好了事务,在注解@Transactional中,自动执行事务,出异常自动回滚,但在使用的时候会遇到一些问题:在多个方法中使用@Transactional,其中一个方法运行时候报错,但是数据却插进去了,但是其他两个方法没有;有时候抛了... 查看详情
为什么事务没有回滚!
...的事务却没有“回滚”,为此还导致了异常数据的发生,为什么?这是一个发生在我工作中的真实的案例,在用户问我的时候我当时也SB了,在我理解了这背后的原理后,我虽然接受了SQLServer在某些场景下不回滚的设计使... 查看详情
事务配置在applicationcontext.xml文件中不起作用,控制不了异常回滚
...事务不会回滚的坑,按道理说,我们配置了事务,在异常发生是,运行时期的异常被我们的框架捕获到,就会为我们做出回滚的操作,但是就是没有,比如博主写的一个简单的转帐的事务,第一个账户的钱被扣除了,但是在执行... 查看详情
spring事务失效的几种场景
...会回滚非检查异常,需要配置rollbackFor属性指定回滚2.业务方法内自己try-cache异常导致事务不能正确回滚事务通知只有捕获到目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知... 查看详情
spring事务失效的几种场景
...会回滚非检查异常,需要配置rollbackFor属性指定回滚2.业务方法内自己try-cache异常导致事务不能正确回滚事务通知只有捕获到目标抛出的异常,才能进行后续的回滚处理,如果目标自己处理掉异常,事务通知无法知... 查看详情
spring管理事务默认回滚的异常
一、默认方式Spring的事务管理默认只对出现运行期异常(java.lang.RuntimeException及其子类),Error进行回滚。 如果一个方法抛出Exception或者Checked异常,Spring事务管理默认不进行回滚。二、改变默认方式 在@Transaction注解中定义no... 查看详情
spring嵌套事务是怎么回滚的?(代码片段)
...两部分:新增用户选课记录课程登记学生数+1新增业务类CourseService实现相关业务逻辑,分别调用了上述方法保存用户与课程的关联关系,并给课程注册人数+1为避免注册课程的业务异常导致用户信息无法保存ÿ... 查看详情
spring事务异常回滚,捕获异常不抛出就不会回滚
...atch,在catch中打印日志。但是这边情况来了,当这个方法异常时候日志是打印了,但是加的事务却没有回滚。 例: 类似这样的方法不会回滚(一个方法出错,另一个方 查看详情
关于抛异常事务回滚的测试(代码片段)
TestController.java代码如下***:/***测试异常回滚.*@return*/@RequestMapping(value="/testExceptionRollBack")@ResponseBodypublicStringtestExceptionRollBack()List<String>idList=Lists.newLinkedList();idList.ad 查看详情
service中事务不能回滚的解决方式(转)
...回滚的 默认spring事务只在发生未被捕获的runtimeexcetpion时才回滚。 springaop 异常捕获原理:被拦截的 查看详情
spring事务失效的几种场景以及原因
...决方案:配置rollbackFor失效原因:spring事务只有捕捉到了业务抛出去的异常,才能进行后续的处理,如果业务自己捕获了异常,则事务无法感知解决方案:1、将异常原样抛出;2、设置TransactionAspectSupport.currentTransactionStatus().setRoll... 查看详情
java编程中,你经常遇到的异常都有哪些?场景如何?
...的几种异常和异常爆发的场景:第一种是算术异常。一般发生的场景是当两数相除,被除数为零时会引发这种错误,这是比较常见的一种错误;第二种是输入不匹配异常,一般发生在本来要你输入整数,结果你却输入了字符,所... 查看详情
java用uilayerexception抛出异常,但是事务没有回滚,已经添加到数据库了
Java用uilayerexception抛出异常,但是事务没有回滚,已经添加到数据库了 @Transactional(rollbackFor=UiLayerException.class) publicvoidsave()throwsUiLayerException if(!"0".equals(cwis_offline)&&!"5".equals(cwis_offline)) thrownewUiLayerException("关... 查看详情
java的几种对象(po,vo,dao,bo,pojo,dto)解释
...对数据库的操作。 二、VO:valueobject值对象。通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要.个人觉得同D 查看详情
java的几种对象(po,vo,dao,bo,pojo,dto)解释
...对数据库的操作。 二、VO:valueobject值对象。通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要.个人觉得同D 查看详情
java的几种对象(po,vo,dao,bo,pojo,dto)解释
...任何对数据库的操作。二、VO:valueobject值对象。通常用于业务层之间的数据传递,和PO一样也是仅仅包含数据而已。但应是抽象出的业务对象,可以和表对应,也可以不,这根据业务的需要.个人觉得同DTO(数据传 查看详情
使用栈处理回滚(代码片段)
...据,两个人同时支付会同时走支付代码,这块还没处理好业务并发,之前考虑加锁,但是这样系统就又变成了单线程执行,后面再考虑方案。)用控制台简单写了一个Demo,计算了一个累加的操作,然后每一步都记录了回滚,每... 查看详情
关于单体测试的事务操作问题
... 会产生以下问题原因:使用单体测试,因为没有经过业务层,所以会产生事务问题,这时候是系统默认的事务,无法做增删改的操作然后我添加了事务,执行操作也显示成功了,可是数据库的数据却没有改变 原因就是虽... 查看详情