首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么我的@Transactional方法在测试时没有回滚?

在Spring框架中,@Transactional注解用于声明事务管理。如果你在测试时发现@Transactional方法没有回滚,可能是以下几个原因:

原因分析

  1. 测试环境配置问题
    • 测试环境可能没有正确配置事务管理器。
    • 测试类或方法上可能没有使用@RunWith(SpringRunner.class)@SpringBootTest注解。
  • 事务传播行为
    • 默认情况下,@Transactional的传播行为是REQUIRED,即如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。如果在一个已经存在的事务中调用另一个带有@Transactional的方法,可能会导致回滚失效。
  • 异常类型
    • @Transactional默认只对RuntimeException及其子类进行回滚。如果你抛出的是Exception或其子类(非RuntimeException),需要显式配置回滚规则。
  • 测试框架的隔离级别
    • 测试框架可能使用了不同的隔离级别,导致事务无法正确回滚。

解决方法

  1. 确保测试环境正确配置
    • 确保测试类上使用了@RunWith(SpringRunner.class)@SpringBootTest注解。
    • 确保测试环境正确配置了事务管理器。
    • 确保测试环境正确配置了事务管理器。
  • 显式配置回滚规则
    • 如果你需要对Exception进行回滚,可以在@Transactional注解中显式配置。
    • 如果你需要对Exception进行回滚,可以在@Transactional注解中显式配置。
  • 检查事务传播行为
    • 确保事务传播行为符合预期,避免在一个已经存在的事务中调用另一个带有@Transactional的方法。
    • 确保事务传播行为符合预期,避免在一个已经存在的事务中调用另一个带有@Transactional的方法。
  • 检查测试框架的隔离级别
    • 确保测试框架使用的隔离级别不会影响事务的回滚。

示例代码

以下是一个完整的示例,展示了如何在测试中正确使用@Transactional注解并确保回滚。

代码语言:txt
复制
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyServiceTest {

    @Autowired
    private MyService myService;

    @Test
    public void testTransactionalMethod() {
        try {
            myService.myTransactionalMethod();
        } catch (Exception e) {
            // 异常被捕获,事务应该回滚
        }
        // 验证数据是否回滚
    }
}

@Service
public class MyService {

    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void myTransactionalMethod() throws Exception {
        // 业务逻辑
        throw new Exception("测试回滚");
    }
}

参考链接

通过以上分析和解决方法,你应该能够解决@Transactional方法在测试时没有回滚的问题。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

为什么加了@Transactional注解,事务没有

在前天《事务管理入门》一文发布之后,有读者联系说根据文章尝试,加了@Transactional注解之后,事务并没有。...问题原因 在前文描述中,漏了一个细节,其实在示例代码中,与之前拿基础例子配置中有一个关键属性没有提到,就是下面这个配置: spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect...这里特地采用了MySQL5InnoDBDialect,主要为了保障使用Spring Data JPA时候,Hibernate自动创建表时候使用InnoDB存储引擎,不然就会以默认存储引擎MyISAM...来建表,而MyISAM存储引擎是没有事务。...所以,如果你事务没有生效,那么可以看看创建表,是不是使用了MyISAM存储引擎,如果是的话,那就是这个原因了! 除此之外,对于事务没有生效可能还很多,比如,同一个类中定义又调用等。

91210

咦,为什么事务不了?

MySQL 事务小伙伴们都懂,通过 begin 开启事务,通过 commit 提交事务或者通过 rollback 事务。...这就意味着带有 DDL 语句事务将来没有办法 rollback。 举一个简单例子,大家一起来看下: 我们来一起看下这里测试逻辑: 首先查询总记录数有四条。 开启一个事务。...。 再次查询数据。 到第六步时候,我们发现查询到数据只剩三条了,说明第五步没有生效。原因就在于执行 alter 之前,事务已经被隐式提交了。...对于上面的案例,如果大家去掉第四步 alter,那么是可以滚成功,这个小伙伴们自己来测试就不演示了。...举个简单例子: 可以看到,跟第一小节测试步骤一样,只不过第四步换成一个 GRANT 语句,那么最终事务也会失效,原因就在于事务已经提交了。

97820
  • java事务案例_java事务控制

    疑问,确实像往常一样service上添加了注解 @Transactional为什么查询数据库还是发现有数据不一致情况,想想肯定是事务没起作用,出现异常时候数据没有。...于是就对相关代码进行了一番测试,结果发现一下踩进了两个坑,确实是事务未导致数据不一致。...Service类内部方法调用 大概就是 Service 中有一个方法 A,会内部调用方法 B, 方法 A 没有事务管理,方法 B 采用了声明式事务,通过方法上声明 Transactional 注解来做事务管理...对于加了@Transactional注解方法来说,调用代理类方法,会先通过拦截器TransactionInterceptor开启事务,然后调用目标类方法,最后调用结束后,TransactionInterceptor...代码中虽然捕获了异常,但是同时也抛出了异常,为什么事务未呢?猜测是异常类型不对,于是开始查询原因,翻看了Spring官方文档,找到了答案。下面是翻译自Spring官网。

    1.6K10

    @Transactional事务几点注意及其属性Propagation使用

    如果加了事务,必须做好开发环境测试测试环境也尽量触发异常、测试),确保事务生效。 C. 以下列了事务使用过程注意事项,请大家留意。 1....5.经过ICORE-CLAIM中测试,效果如下: A.抛出受查异常XXXException,事务会。 B.抛出运行时异常NullPointerException,事务会。...(即上文3点提到) D.异步任务中,execute直接调用加了@Transactional方法,可以;间接调用,不会。...F.service中加上@Transactional,如果是action直接调该方法,会,如果是间接调,不会。...主要用来配置当前需要执行方法,与当前是否有transaction之间关系。 晓得有点儿抽象,这也是为什么想要写这篇博客原因。看了后面的例子,大家应该就明白了。

    1.4K20

    @Transactional加不加rollbackFor=Exception.class区别?

    上周,一同事看到我去年写一些代码,@Transactional 加上了 rollbackFor,就问我为什么当时和他解释了一番,这里分享出来,希望能够帮助到更多的人。...准备数据 首先 Mysql 中准备了一条数据,如下所示: 开始测试 下面我们就开始简单粗暴测试了。 我们目的是需要把delflag修改为 0,简单准备一下 sql。...@Transactional且不加rollbackFor,然后抛出上面的异常,数据库滚了。...原因是:@Transactional默认异常就RuntimeException类型。只要是RuntimeException类型,和它子类型异常,默认都能。...这个时候我们去看一下数据库值到底有没有修改成功,很显然数据是被滚了。并没有修改成0。 下面我们再试试@Transactional不能异常。

    1.6K30

    测试移动弱网踩过坑|洞见

    为何要进行弱网测试 当前所在项目的产品是一款适配于低资源环境医疗IT系统,目前主要是坦桑尼亚地区使用。...弱网测试碰到问题和解决方案 1、现象:用户登录应用时下载初始化数据,下载过程中因网速太慢点击取消并重新登录,数据初始化完成后出现重复,造成数据不一致。...原因:数据下载过程中、下载失败后,未进行数据,中止后重新下载,出现数据重复。 解决方案 :通过事务处理数据下载逻辑,下载失败后,应用本地数据库进行数据。...5、现象:弱网络环境下,用户请求页面响应时间较长,等待过程中,页面上部分控件仍然可以操作,当用户点击控件,出现应用闪退现象; 原因:没有对数据加载流程进行判断,直接暴露控件可控,当出现依赖数据控件操作...6、现象:弱网环境下,用户第一次输入搜索关键字没有得到响应后,再次输入全新关键字并发送请求,等待搜索结果返回后,当前结果页被之前关键字搜索结果刷新覆盖。

    2.2K60

    日常开发踩坑:你事务真的奏效了吗?

    ..... } 再次测试:发生异常情况下,数据依然没有!...这又是为什么呢? 原因在于:注解方式事务声明@Transactinal是基于AOP,而AOP底层是通过动态代理模式来实现,也就是说事务逻辑其实是存在于代理类方法增强逻辑中。...坑点:声明事务方法发生指定抛出异常类型,事务无法。...解决方案:@Transactional注解中声明事务支持异常类型 @Transactional(rollbackFor = Exception.class) 3 嵌套事务逻辑错误...public boolean insertLog(){ logDao.insertLog(); } } 通过代码可以看到,主事务方法中包含了日志入库子事务方法,那么当子事务

    32320

    日常开发踩坑:你事物真的奏效了吗?

    ..... } 再次测试:发生异常情况下,数据依然没有!...这又是为什么呢? 原因在于:注解方式事物声明@Transactinal是基于AOP,而AOP底层是通过动态代理模式来实现,也就是说事物逻辑其实是存在于代理类方法增强逻辑中。...坑点:声明事物方法发生指定抛出异常类型,事物无法。...解决方案:@Transactional注解中声明事物支持异常类型 @Transactional(rollbackFor = Exception.class) 3 嵌套事物逻辑错误...public boolean insertLog(){ logDao.insertLog(); } } 通过代码可以看到,主事物方法中包含了日志入库子事物方法,那么当子事物

    26520

    程序员新人周一优化一行代码,周三被劝退?

    事务执行过程中发生错误,会被(Rollback)到事务开始前状态,就像这个事务从来没有执行过一样。 一致性(Consistency):事务开始之前和事务结束以后,数据库完整性没有被破坏。...不可重复读是指,一个事务内,多次读同一数据,在这个事务还没有结束,如果另一个事务恰好修改了这个数据,那么,第一个事务中,两次读取数据就可能不一致。...幻读是指,一个事务中,第一次查询某条记录,发现没有,但是,当试图更新这条不存在记录,竟然能成功,并且,再次读取同一条记录,它就神奇地出现了。...事务超时时间 事务超时,也就是指一个事务所允许执行最长时间,如果在超时时间内还没有完成的话,就自动。...事务策略 默认情况下,事务只在出现运行时异常(Runtime Exception),以及 Error,出现检查异常(checked exception,需要主动捕获处理或者向上抛出)不回

    29630

    使用ES

    如上图,新增卡片时,先做了数据库插入,然后做ES插入,最后做事件通知及其他操作。看着好像也没什么问题。 等等,不对,为什么这里没做事务管理?如果有事务,失败了不就会么?...看来问题根源找到了: 用户操作新增卡片时,先往数据库插了条数据,然后ES上也增加了对应数据,但是在做事件更新,出了问题(第1步报错信息来源于此),触发了@Transactional事务机制...但是由于ES不支持事务,所以@Transactional也没办法,所以列表中数据还是能被查看到(第2步,ES中数据还是),但是点击详情(第3步),因为在数据库中找不到对应数据,所以页面无法显示...异常类中统一处理,如果发现这个方法有异常抛出,就记录数据信息,去ES中做对应回退操作(分类处理,例如数据库是insert操作,就调用ESdelete操作数据删除),人为实现ES; 3....对于事务一致性测试平时很容易被忽略,大家都还是相信开发会使用事务。但是对于事务管理是否会失效,没有引起足够重视。 对于测试人员而言,常见事务一致性测试场景有哪些呢? a.

    53830

    深入理解 Spring 事务:入门、使用、原理

    NESTED NESTED 也是常用一个传播类型,该方法特性与 REQUIRED 非常相似,其特性是:当前方法存在事务,子方法加入嵌套事务执行。当父方法事务,子方法事务也跟着。...而 REQUIRED 则是:父方法发生异常回,子方法事务会。而子方法事务发送回,父事务是否取决于是否捕捉了异常。 为了验证 NESTED 事务传播类型特点,我们来做几个测试。...这说明父方法发送异常,子方法事务会。 接着,我们继续验证一下:当子方法事务发生异常,如果父方法没有捕捉异常,父方法事务是否会?...这说明子方法发送异常回,如果父方法没有捕捉异常,那么父方法事务也会。 最后,我们验证一下:当子方法事务发生异常,如果父方法捕捉了异常,父方法事务是否会?...此时父子方法事务独立,它们都不会相互影响。但父方法需要注意子方法抛出异常,避免因子方法抛出异常,而导致父方法。 NESTED 当前方法存在事务,子方法加入嵌套事务执行。

    3K20

    详解事务7种传播行为

    事务传播行为是指多个拥有事务方法嵌套调用时事务控制方式 比如XML中配置:XML: 注解配置:@Transactional...疑问:异常继续往上抛父方法才知道发生了异常,导致方法里所有数据库操作,那么把这个异常try-catch,是不是就只有saveChildren()呢?那可不一定,跟着继续来看。...saveChildren()产生异常被捕获,没有继续上抛,父方法开启事务不会,故插入2条数据。...子方法saveChildren()支持父事务,故使用事务,saveChildren()发生异常回,这里子事务没将父事务挂起,子事务,父事务一定,正好验证了前面说过结论,所以这里没有记录...原来事务都挂起了,子事务和父事务没有必然联系了。 其实这里原因是因为异常抛给了父事务,导致

    61610

    事务一致性测试

    如上图,新增卡片时,先做了数据库插入,然后做ES插入,最后做事件通知及其他操作。看着好像也没什么问题。 等等,不对,为什么这里没做事务管理?如果有事务,失败了不就会么?...看来问题根源找到了: 用户操作新增卡片时,先往数据库插了条数据,然后ES上也增加了对应数据,但是在做事件更新,出了问题(第1步报错信息来源于此),触发了@Transactional事务机制...但是由于ES不支持事务,所以@Transactional也没办法,所以列表中数据还是能被查看到(第2步,ES中数据还是),但是点击详情(第3步),因为在数据库中找不到对应数据,所以页面无法显示...异常类中统一处理,如果发现这个方法有异常抛出,就记录数据信息,去ES中做对应回退操作(分类处理,例如数据库是insert操作,就调用ESdelete操作数据删除),人为实现ES; 3....对于事务一致性测试平时很容易被忽略,大家都还是相信开发会使用事务。但是对于事务管理是否会失效,没有引起足够重视。 对于测试人员而言,常见事务一致性测试场景有哪些呢? a.

    29920

    一个@Transaction哪里来这么多坑?

    但根据之前分析我们知道,实际上调用saveB方法,是直接调用目标类中saveB方法saveB方法前后并不会有事务开启或者提交、等操作,实际流程是下面这样 ?...如果你看过之前源码分析文章应该知道,处理时有这么一段代码 ? rollBackOnly设置 提交又做了下面这个判断(这个方法删掉了一些不重要代码) ?...当传播级别为requires_new,两个事务完全没有联系,各自都有自己事务管理机制(开启事务、关闭事务、事务)。...但是传播级别为nested,实际上只存在一个事务,只是调用a方法设置了一个保存点,当a方法,实际上是滚到保存点上,并且当外部事务提交,内部事务才会提交,外部事务如果,内部事务会跟着...显示 最大区别在于处理第二个参数传入是false,这意味着是预期之中,所以处理完后并不会抛出异常。

    1K40

    Spring声明式与编程式事务区别,事务与非事务方法相互调用导致事务不生效问题

    目标方法执行前加入或创建一个事务,执行方法执行后,根据实际情况选择提交或是事务。 使用这种方式,对代码没有侵入性,方法内只需要写业务逻辑就可以了。...saveB(B b){ dao.saveB(a); } } 实际上调用 saveB 方法,是直接调用目标类中 saveB 方法 saveB 方法前后并不会有事务开启或者提交、等操作...如果你看过之前源码分析文章应该知道,处理时有这么一段代码 rollBackOnly 设置 提交又做了下面这个判断(这个方法删掉了一些不重要代码) commit_rollbackOnly...但是传播级别为 nested ,实际上只存在一个事务,只是调用 a 方法设置了一个保存点,当 a 方法,实际上是滚到保存点上,并且当外部事务提交,内部事务才会提交,外部事务如果,内部事务会跟着...这样当提交事务时会进入下面这段代码 显示 最大区别在于处理第二个参数传入是 false, 这意味着是预期之中,所以处理完后并不会抛出异常。

    1.3K41

    关于spring事务你需要知道知识点

    事务失效了,这一次userDao是自己创建实例,而不是动态代理类。 动态代理类,使用@Transactional方法,前置通知开启事务,后置通知决定是提交还是。...2)修饰非public方法 如果@Transactional修饰非public修饰方法上,事务将会失效。...使用@Transactional,使用到public方法上。所以这也是不建议将注解使用在类上原因,你以为类中方法都有事务了,但实际不然。...} /** * 外部方法没有事务,内部方法会创建一个新事务 * 如果发生异常,只会导致自己所在方法事务 * 这里创建了两个事务 */...我们将外部方法事务称为父事务,内部方法创建事务为子事务 当子事务,不影响父事务 当父事务,子事务一起 这里同样,我们来进行测试一下 package com.banmoon.test.service

    30820

    @Transactional注解不起作用解决办法及原理分析

    ,导致事务没开启,因此方法抛出异常,testMapper.insert(new Test(10,20,30));操作不会进行。...} } 上面就是使用测试代码,运行测试知道,外部调用事务方法能够征程开启事务,testMapper.insert(new Test(10,20,30))操作将会被; 然后运行另外一个测试用例,调用一个方法类内部调用内部被...第三种 事务方法内部捕捉了异常,没有抛出新异常,导致事务操作不会进行。 示例代码如下。...,虽然抛出异常,但是异常被捕捉了,没有抛出到方法 外, testMapper.insert(new Test(210,20,30))操作并没有。...~ 第三种 事务方法内部捕捉了异常,没有抛出新异常,导致事务操作不会进行

    80730

    Spring事务和事务传播机制(1)

    Spring事务管理提供了灵活方式来处理事务,包括事务创建、提交、以及事务传播行为。 一、为什么需要事务?...3、Spring 声明式事务(自动) 声明式事务实现很简单,只需要在需要方法上添加 @Transactional 注解就可以实现了,无需手动开启事务和提交事务,进入方法自动开启事务,方法执行完会自动提交事务...,方法中使用TransactionAspectSupport.currentTransactionStatus() 可 以得到当前事务,然后设置方法 setRollbackOnly 就可以实现滚了...@Transactional 开始执行业务之前,通过代理先开启事务,执行成功之后再提交事务。如果中途遇到异常,则事务。...事务执行过程中发生错误,会被(Rollback)到事务开始前状态,就像这个事务从来没有执行过⼀样。 ⼀致性:事务开始之前和事务结束以后,数据库完整性没有被破坏。

    21440
    领券