【问题标题】:Transactional test can't update/delete事务测试无法更新/删除
【发布时间】:2021-12-28 12:52:57
【问题描述】:

我有一个@Repository,它有几个不同的查询来更新表。这些方法没有使用@Transactional 注释,因为事务处于服务级别。

我想测试这些存储库。我创建了一个带有 @Transactional 注释的测试类,但是当调用存储库方法时,它们会失败:

Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

如果我用@Transactional 注释每个存储库方法,它会修复错误,但我不想更改主代码库。我应该能够在测试中创建事务。

我创建了一些示例代码来展示我的一般结构。

存储库

@Repository
public class ExampleRepo extends JPARepository<X, Y> {

    // Adding @Transactional here fixes the test
    @Modifying
    @Query("update Example e set e.example=:example where e.id = :id")
    int exampleQuery(@Param("example") String example, @Param("id") int id);
}

测试

@Transactional
@SpringBootApplication
@SpringBootTest
public class RepoTest {
    
    private final ExampleRepo repository;

    @Autowired
    public RepoTest(final ExampleRepo repository){
        this.repository = repository;
    }

    
    @Test
    void testExample() {
        // Fails
        repository.exampleQuery("example", 1);
    }
}

例外

Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query
org.springframework.dao.InvalidDataAccessApiUsageException: Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

不应该将测试注释为 `@Transactional' 来解决这个问题吗?

我能找到的所有示例都使用它。如果我用@Transactional 注释每个单独的测试,它仍然会失败。

【问题讨论】:

    标签: java spring spring-boot spring-transactions


    【解决方案1】:

    你为什么用@SpringBootApplication注释你的测试类?不推荐!无论如何,它可能只是为了快速测试。我不知道你到底想测试什么方法,但例如测试下面代码的保存方法是一个好方法,试试看它是否适合你。

    @SpringBootTest
    @RunWith(SpringRunner.class)
    public class RepoTest {
    
        @Autowired
        private ExampleRepo repository;
    
        @Test
        @Transactional
        public void save_() {
            Object savedObj = repository.save(entity);
            assertNotNull(savedObj.getId());
        }
    }
    

    【讨论】:

    • 由于项目被拆分为多个模块,因此使用 @SpringBootApplication 进行注释。此项目中没有定义@SpringBootApplication,因为它仅用于存储库/服务。
    • 我已经尝试使用@Transactional 编写这个方法,但它仍然有同样的错误。此外,如果我尝试使用TestTransaction.start(),它会显示Cannot start a new transaction without ending the existing transaction first。所以看起来有一笔交易。
    • 要符合 JPA,您应该使用 javax.transaction.Transactional,尽管在某些版本中,如果 javax.transaction.Transactional 导致问题的 spring-data 组合,您可以尝试使用 org.springframework.transaction.annotation.Transactional
    • 我正在使用org.springframework.transaction.annotation.Transactional。抱歉,我应该复制导入。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-03-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-24
    • 2014-01-27
    • 2023-04-06
    相关资源
    最近更新 更多