【问题标题】:Spring Data test repository with propagation setting具有传播设置的 Spring Data 测试存储库
【发布时间】:2021-09-17 11:10:52
【问题描述】:

这是一个测试类:

@SpringBootTest
@AutoConfigureMockMvc
@Transactional
public class ValidationTest {
  @Autowired
  private EntityManager entityManager
  ...
}

我想测试服务:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public boolean isEmailUnique(String emailAddress) {
  Optional<User> user = userRepository.findByEmail(emailAddress);
  ...
}

为此,我创建并保存了一个实体:

entityManager.persist(new User(name: "abc", email: "abc@email.com"))
entityManager.flush()

最后调用请求:

mockMvc.perform(post("..."))

userRepository.findByEmail() 看不到插入的实体,我错过了什么? ps:如果我从方法中删除@Transactional,那么测试工作正常。

【问题讨论】:

    标签: java spring-boot spring-transactions spring-boot-test


    【解决方案1】:

    你的行为环境很难理解,因为你只提供了一些摘录!但据我所见,我猜……

    如果您使用@Transactional 注释您的测试,则每个测试方法都会被一个新事务包围,该事务会在测试方法执行后自动回滚。

    如果您现在在测试方法中准备一些数据,则它在隐式创建的事务范围内是可见的。如果您随后调用您的服务方法并且此服务方法想要进行新事务,则此新事务不会“看到”您在外部事务中准备的数据。如果您从服务方法中删除 @Transactional 注释,存储库现在可以“看到”数据。

    如果您查看Propagation 枚举的javadoc,您会看到PROPAGATION_REQUIRES_NEW 是这样描述的:

    Create a new transaction, and suspend the current transaction if one exists.
    

    问题是,为什么他们一定需要一个新的交易,即使一个已经存在?如果还没有可用的,他们不能只创建一个新的,但如果已经存在,就使用现有的吗? SUPPORTS 传播就是这种情况,默认情况下在 @Transactional 注释上配置。

    【讨论】:

    • 谢谢!我必须在服务方法甚至userRepository.findByEmail 上单独添加Propagation.REQUIRES_NEWNOT_SUPPORTED 才能在验证期间使用此调用。如果我保留单个事务,那么 spring 会将数据保存到 db 中,然后才使用其中的另一个 db-request 调用验证。
    • 好吧,同意。我的错。我想我应该将测试分成两部分,并在测试前自行准备数据。然后它应该是可见的。
    猜你喜欢
    • 2014-06-19
    • 1970-01-01
    • 2019-01-23
    • 2012-05-06
    • 2021-01-28
    • 1970-01-01
    • 2020-02-24
    • 2019-03-22
    • 1970-01-01
    相关资源
    最近更新 更多