如何将数据刷新到活动弹簧事务中的数据库?

我想使用弹簧测试框架测试休眠会话的save()方法。@Test方法是:

@Test
@Transactional
public void testSave() {
    User expected = createUser();
    getGenericDao().currentSession().save(expected);
    User actual = getUser(generatedId);
    assertUsersEqual(expected,actual);
}

我想将用户刷新到数据库中。我希望我的用户在此方法之后在数据库中

getGenericDao().currentSession().save(expected);

然后我想使用spring数据框架转到数据库,并通过下一行获取此保存的用户:

User actual = getUser(generatedId);

我试图使用休眠冲洗方法,如:

currentSession().setFlushMode(MANUAL);
//do saving here
currentSession().flush();

它不会将我的用户刷新到数据库中!但是,如果我不使用@Transactional弹簧注释并将我的用户保存在程序化的弹簧事务中,我就会实现我想要的。不幸的是,保存到db中的用户不会回滚,因为没有弹簧@Transactional。因此,我的测试方法改变了后续测试方法的数据库和行为。

因此,我需要将我的用户刷新到测试方法内部的数据库(而不是在末尾),并在测试方法结束时回滚对db的所有更改。

更新建议准备方法如下:

@Transactional
public void doSave(User user){
    getGenericDao().currentSession().save(user);
}

而调用 doSave 在 testSave 里面什么都不做。执行此方法后,我在数据库中仍然没有用户。我设置断点并从命令行检查我的数据库。

更新非常感谢您的回复。问题是方法 flush() 不会将我的用户放入数据库。我尝试Isolation.READ_UNCOMMITTED,它没有将我的用户放入数据库。我可以实现我想要的,但前提是我关闭@Test方法的弹簧交易,并在编程交易中进行保存。但是,@Test方法不会回滚,将保存的用户留给后续@Test方法。这里@Test保存用户的方法不如@Test删除用户的方法危险,因为它不会回滚。因此,必须对@Test方法进行弹簧事务支持,无论如何我都无法将我的用户(或删除)放入db中。实际上,只有在@Test方法结束并且@Test方法的事务被委托后,才会将用户放入(或删除)到数据库中。因此,我想在方法的中间将我的用户保存到@Test数据库中,并在@Test方法结束时回滚它

谢谢!


答案 1

最后,我坚持以下解决方案:

首先,我的方法不在弹簧支撑下运行。请参阅此文章以了解它可能有多危险。接下来,我不再在方法中使用bean,而是自动连接使用注释的bean。奇迹就是这样的方法@Test@Transactional@Repository@Test@Service@Transactional@Test

@Test
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void testSave() {
    Answer created = createAnswer();
    Long generatedId = answerService.save(created);
//at this moment answer is already in db
    Answer actual=getAnswerById(generatedId);
... }

将我的 Answer 对象放入数据库(紧随其后),方法转到 DB 并提取它以检查保存是否正确。
为了消除在方法中对数据库所做的更改,我通过以下方式重新创建数据库answerService.save(created);getAnswerById@TestJdbcTestUtils.executeSqlScript


答案 2
  1. 看看这里关于测试的警告(春季陷阱:交易测试被认为是有害的)。我曾经在我的服务测试和控制器中重新填充DB。@Transactional@org.springframework.test.context.jdbc.Sql@Transactional
  2. ConstraintViolationException对于控制器,仅当提交事务时才引发具有无效数据的更新测试。所以我找到了3个选项:
    • 2.1 使用 或 使用 注释测试。注意数据库更改。@Commit@Transactional(propagation = Propagation.NEVER)
    • 2.2 使用TestTransaction

法典:

     TestTransaction.flagForCommit();
     TestTransaction.end();
  • 2.3 使用TransactionTemplate

法典:

    @Autowired
    private PlatformTransactionManager platformTransactionManager;

    @Test(expected = Exception.class)
    public void testUpdate() throws Exception {
        TransactionTemplate transactionTemplate = new TransactionTemplate(platformTransactionManager);
        transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
        String json = ...
        transactionTemplate.execute(ts -> {
            try {
                mockMvc.perform(put(REST_URL + USER_ID)
                    .contentType(MediaType.APPLICATION_JSON)
                    .content(json))
                    .andExpect(status().isOk());
                ...
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        });

推荐