Spring-Java事物回滚失效处理

本文探讨了Java中Spring事务管理的回滚机制,重点讲解了检查型异常与非检查型异常的区别及其对事务回滚的影响,并提供了具体的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring-Java事物回滚失效处理最近在做项目中,无意间发现有个类在抛事物回滚操作,数据也正常的插入到数据库当中了,于是仔细查看看一下具体原因。

一切还是要从Java的检查型异常和非检查型异常说起。

那么什么是检查型异常什么又是非检查型异常呢?
 最简单的判断点有两个:
    1.继承自RuntimeException或Error的是非检查型异常,而继承自Exception的则是检查型异常(当然,RuntimeException本身也是Exception的子类)。
    2.对非检查型类异常可以不用捕获,而检查型异常则必须用try……catch语句块进行处理或者把异常交给上级方法处理,总之就是必须写代码处理它。

Java 的异常结构如下图。其中直接继承Exception的异常,必须捕获,属于检查型异常。


再回过来看我的代码:

1、方法名前面有

@Transactional

2、Spring的配置文件applicationContext-XXX.xml当中也有Spring事物的相关配置

    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
        <property name="rollbackOnCommitFailure" value="true"></property>
    </bean>


但是为什么在Service层方法调用的时候,try……catch抛Exception异常已经提交的事物却没有回滚?

查看相关spring的文档后发现,原来spring声明式事务管理默认对非检查型异常和运行时异常进行事务回滚,而对检查型异常则不进行回滚操作。

代码中try……catch抛出的Exception异常,属于检查型异常,Spring的框架默认是不会进行回滚的。

在编程中对非检查型类异常可以不用捕获,而检查型异常则必须用try语句块进行处理或者把异常交给上级方法处理总之就是必须写代码处理它。

所以必须在service捕获异常,然后再次手动 throw 一个非检查型异常,这样事务方才起效。例如:

try{
    …………
} catch (Exception e) {
    …………
    throw new BusinessException(e.getMessage());
}


当然我们还有更简便的方法来解决这个问题,那就是通过注解参数改变默认的回滚方式 。

在@Transaction注解中定义了noRollbackFor和RollbackFor来指定某种异常是否回滚。

使用例:

    @Transaction(noRollbackFor=RuntimeException.class)

    @Transaction(RollbackFor=Exception.class)

所以上述的问题可以直接将@Transaction添加回滚参数@Transaction(RollbackFor=Exception.class) ,这样就改变了默认的事务处理方式。


启示 :

这就要求我们在自定义异常的时候,让自定义的异常继承自RuntimeException,这样抛出的时候才会被Spring默认的事务处理准确处理。




<think>嗯,用户问的是Spring事务的传播,需要我来解释一下。首先,我得回忆一下Spring事务传播类有哪些。记得有七种,但具体名称可能记不全。比如REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,还有NESTED。对吧? 然后,用户可能是刚接触Spring事务,或者在实际开发中遇到了问题,比如多个事务方法相互调用时出现异常回滚的情况。需要理解不同的传播机制如何影响事务边界和行为。 接下来,我应该逐一解释每个传播类,最好用简单的中文和例子。比如REQUIRED是默认的,如果当前有事务就加入,没有就新建。REQUIRES_NEW则是无论当前有没有事务,都新建一个,这样外层事务的回滚不会影响内层。这可能容易混淆,需要区分清楚。 用户可能需要知道在什么场景下使用哪种传播类。例如,在记录日志的时候,即使主事务回滚,日志还是需要保存,这时候可以用REQUIRES_NEW。而NESTED允许嵌套事务,回滚到保存点,这在部分操作需要独立回滚时有用。 需要注意的是,NESTED只适用于某些事务管理器,比如DataSourceTransactionManager,而REQUIRES_NEW可能更通用。同时,不同的传播行为对异常处理的影响也不同,比如检查异常和非检查异常是否会触发回滚。 可能用户没有提到事务的隔离级别和超时设置,但传播机制是核心。要确保解释清晰,避免术语过多,适当举例帮助理解。比如两个Service方法调用,不同的传播类如何组合,事务如何提交或回滚。 最后,总结一下使用场景,帮助用户根据需求选择合适的传播类。确保回答结构清晰,分点说明,这样用户容易查阅。检查有没有遗漏的类,或者是否有常见的错误理解需要纠正,比如SUPPORTS和NOT_SUPPORTED的区别。</think>Spring 事务传播(Transaction Propagation)是 Spring 框架中管理事务行为的重要机制,用于定义多个事务方法相互调用时,事务应该如何传播和协调。以下是 Spring 事务的 7 种传播行为及其使用场景的简要介绍: --- ### 1. **`REQUIRED`(默认值)** - **规则**:如果当前存在事务,则加入该事务;如果不存在,则新建一个事务。 - **场景**:适用于大多数业务方法,如订单创建后需要更新库存,两者应在同一事务中完成。 - **示例**: ```java @Transactional(propagation = Propagation.REQUIRED) public void methodA() { // 如果 methodB 被 methodA 调用,methodB 会加入 methodA 的事务 methodB(); } ``` --- ### 2. **`REQUIRES_NEW`** - **规则**:无论当前是否存在事务,都新建一个事务。如果已有事务,则挂起旧事务。 - **场景**:需要独立提交的事务,如日志记录(即使主事务回滚,日志仍需保存)。 - **示例**: ```java @Transactional(propagation = Propagation.REQUIRES_NEW) public void logActivity() { // 独立事务,不受外层事务回滚影响 } ``` --- ### 3. **`SUPPORTS`** - **规则**:如果当前存在事务,则加入事务;如果不存在,则以非事务方式执行。 - **场景**:适用于查询方法,可以灵活适应调用方的事务状态。 - **示例**: ```java @Transactional(propagation = Propagation.SUPPORTS) public void queryData() { // 如果调用方有事务,则加入;否则直接执行 } ``` --- ### 4. **`MANDATORY`** - **规则**:强制要求当前必须存在事务,否则抛出异常- **场景**:确保方法必须在事务中被调用,如核心业务逻辑。 - **示例**: ```java @Transactional(propagation = Propagation.MANDATORY) public void criticalOperation() { // 如果无事务,直接抛出异常 } ``` --- ### 5. **`NOT_SUPPORTED`** - **规则**:以非事务方式执行,如果当前存在事务,则挂起该事务。 - **场景**:执行不需要事务的操作(如调用外部 API)。 - **示例**: ```java @Transactional(propagation = Propagation.NOT_SUPPORTED) public void callExternalService() { // 即使外层有事务,此处也无事务 } ``` --- ### 6. **`NEVER`** - **规则**:强制要求当前不能存在事务,否则抛出异常- **场景**:确保方法不会在事务中执行,如性能敏感的批量操作。 - **示例**: ```java @Transactional(propagation = Propagation.NEVER) public void batchProcess() { // 如果存在事务,抛出异常 } ``` --- ### 7. **`NESTED`** - **规则**:如果当前存在事务,则在嵌套事务中执行(基于保存点 Savepoint)。嵌套事务回滚不会影响外层事务,但外层事务回滚会连带嵌套事务回滚- **场景**:部分操作需要独立回滚(如订单中的多个子操作)。 - **注意**:需事务管理器支持(如 `DataSourceTransactionManager`)。 - **示例**: ```java @Transactional(propagation = Propagation.NESTED) public void subOperation() { // 嵌套事务,独立回滚 } ``` --- ### **关键点总结** - **默认行为**:`REQUIRED` 是大多数场景的选择。 - **事务独立性**:`REQUIRES_NEW` 和 `NESTED` 可实现部分操作独立提交或回滚- **事务依赖**:`MANDATORY` 和 `NEVER` 用于强制校验事务是否存在。 - **非事务执行**:`SUPPORTS` 和 `NOT_SUPPORTED` 用于灵活控制事务边界。 合理选择传播行为可以避免事务失效、数据不一致等问题,需结合具体业务场景设计。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值