[英]How to flush data into db inside active spring transaction?
我想使用spring测试框架测试hibernate session的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);
我尝试使用hibernate flush方法,如:
currentSession().setFlushMode(MANUAL);
//do saving here
currentSession().flush();
它不会将我的用户刷新到数据库中! 但是,如果我不使用@Transactional spring注释并将我的用户保存在编程弹簧事务中,我就能实现我想要的。 不幸的是,由于没有spring @Transactional,因此保存到db的用户不会回滚。 因此,我的测试方法会更改后续测试方法的db和行为。
所以我需要将我的用户刷新到db里面的测试方法(不是在最后),并在测试方法结束时回滚所有对db的更改。
UPDATE建议准备方法如下:
@Transactional
public void doSave(User user){
getGenericDao().currentSession().save(user);
}
并且在testSave中调用doSave什么都不做。 执行此方法后,我仍然没有db中的用户。 我设置断点并从命令行检查我的数据库。
更新非常感谢您的回复。 问题是方法flush()不会将我的用户放入数据库。我尝试了Isolation.READ_UNCOMMITTED并且它没有将我的用户放入数据库。 我可以实现我想要的,但前提是我在@Test方法上关闭spring事务并在程序化事务中保存。 然后@Test方法不回滚,为后续的@Test方法留下保存的用户。 这里保存用户的@Test方法不像删除用户的@Test方法那样危险,因为它没有回滚。 因此必须对@Test方法提供Spring事务支持,我无法将我的用户(或删除)放入db。 实际上,只有在@Test方法结束并且@Test方法的事务被调用后,才会将用户放入(或删除)到db中。 所以我想在@Test方法的中间将我的用户保存到db中,并在@Test方法结束时回滚它
谢谢!
最后我坚持以下解决方案:
首先,我的@Test
方法没有在spring @Transactional
支持中运行。 请参阅此文章以了解它可能有多危险。 接下来,不是在@Test
方法中使用@Repository
bean,而是使用@Transactional
注释自动装配@Service
bean。 奇迹是像这样的@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对象放入数据库(就在answerService.save(created);
)之后,方法getAnswerById
转到DB并提取它以检查保存是否正确。
为了消除在@Test
方法中对数据库所做的更改,我通过JdbcTestUtils.executeSqlScript
重新创建数据库
@Transactional
测试的警告( Spring Trafalls:交易测试被认为是有害的 )。 我已经使用@org.springframework.test.context.jdbc.Sql
在我的服务测试中重新填充数据库,为控制器重新填充@Transactional
。 ConstraintViolationException
。 所以我找到了3个选项:
@Commit
或@Transactional(propagation = Propagation.NEVER)
注释测试。 注意DB更改。 TestTransaction
码:
TestTransaction.flagForCommit();
TestTransaction.end();
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;
});
如果flush
不起作用,那么它在很大程度上取决于您的数据库隔离级别。
Isolation
是数据库的ACID
属性之一,它定义了一个操作所做的更改如何/何时对其他并发操作可见。
我相信您的隔离级别设置为Read Committed
或Repeatable Read
。
您还应该注意importpackage:在我的情况下我导入了
import javax.transaction.Transactional;
代替
import org.springframework.transaction.annotation.Transactional;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.