在spring引导应用程序中在事务中包装多个调用?
我在spring应用程序中使用jdbctemplate对db执行查询 下面是用@Transactional注释的方法在spring引导应用程序中在事务中包装多个调用?,spring,spring-boot,spring-transactions,Spring,Spring Boot,Spring Transactions,我在spring应用程序中使用jdbctemplate对db执行查询 下面是用@Transactional注释的方法 @Transactional public boolean doSomething(){ try { jdbcTemplate.update(sql1); //1 jdbcTemplate.update(sql2); //2 jdbcTemplate.update(sql3); //3 return
@Transactional
public boolean doSomething(){
try {
jdbcTemplate.update(sql1); //1
jdbcTemplate.update(sql2); //2
jdbcTemplate.update(sql3); //3
return true;
} catch (Exception ex){
return false;
}
}
我的问题是,如果1和2成功而3失败,1和2上的事务是否会回滚?我如何测试这个
此外,使用布尔值作为返回值是否是指示事务状态的良好做法?如果3失败,1和2将回滚。这是事务(工作单元)的核心点。
基于@Zergleb答案的重要更正:仅当您抛出异常时。在您的代码中,您正在咀嚼异常,因此1和2将持续存在,因为事务没有“看到”异常,所以它不知道发生了什么错误 要进行测试,请在
sql3
中放入一些无效的sql,看看会发生什么
我通常不会返回布尔值来表示成功。成功是方法的成功完成,相反,您应该让异常冒泡,或者用更合适的方式包装异常并抛出它,如果您的场景指示这样做的话
例如:
@Transactional
public void doSomething(){
try {
jdbcTemplate.update(sql1); //1
jdbcTemplate.update(sql2); //2
jdbcTemplate.update(sql3); //3
} catch (Exception ex){
throw new MyCustomPersistenceException("Could not doSomething", e);
}
}
如果1和2成功而3失败,1和2上的事务是否回滚 如果第三个操作失败,将回滚第一个和第二个操作。但如果它们是同一事务或事务上下文的一部分 例如,如果将事务管理器定义为DataSourceTransactionManager,它将回滚同一连接的JDBC操作。在您的例子中,这三个操作都在同一个方法中,并且使用同一个jdbcTemplate,因此它将回滚其他两个事务 如果使sql指令失败,则可以对此进行测试,例如:
@Transactional
public void doSomething(){
try {
jdbcTemplate.update(sql1); //1
jdbcTemplate.update(sql2); //2
jdbcTemplate.update(sql3); //3
} catch (Exception ex){
throw new MyCustomPersistenceException("Could not doSomething", e);
}
}
关于返回布尔值,我认为最好抛出一个异常,它将自动回滚事务。否!如果捕获到异常,您的sql将不会回滚强> 这不会触发回滚。您需要删除try catch。但是,如果抛出运行时异常,这些将按预期回滚。请参考以下文档 @事务设置 您将看到下面几行,回滚是由任何RuntimeException触发的。因此,如果捕获到异常,它将不会触发回滚,当返回false时,它将简单地结束事务。请进一步注意,如果抛出选中的异常,它将不会回滚,因此不要试图通过抛出异常来修复此问题,以便对该布尔返回值执行任何操作 我自己还没有尝试过这个方法,但是如果您在@Transactional上设置rollbackFor属性,或者可能只是在这个方法的外部捕获RuntimeException,那么您似乎可以回滚检查过的异常?或者抛出自己的运行时异常?我把这个留给你 如上所述,这也适用于存储库,您可以在这里看到一个示例 Spring数据(存储库)事务
那么,您的意思是不要尝试/catch在
@Transactional
方法中执行,而让调用者来处理执行?另外,如果我不返回布尔值,我应该返回什么?您可以尝试/捕获,我将添加一个示例来回答。至于退货类型,依我看,这在你的情况下应该是无效的。在某些情况下,如果持久化改变了状态(例如分配一个id),插入/更新类型方法可能会返回持久化对象。此外,@Zergleb的回答指出了我错过的一些非常重要的东西。如果不抛出异常,事务代码将不会看到问题,并提交。换句话说,它只有在出现异常时才会回滚。如果我将jdbcTemplate调用包装到存储库中会怎么样?例如,我的代码是repository.callUpdate();respository.callInsert();callDelete()代码>但在下面,存储库使用的是相同的JDBCTemplate在这种情况下,最好使用PlatformTransactionManager,并且您的应用程序服务器需要支持JTA。只是好奇为什么,我仍然在@Transactional
中包装所有存储库调用。我不确定这些调用是否在同一会话中进行。我认为每次调用都会创建一个新会话。因此,如果需要更广泛的事务上下文,您需要JTA。此外,如果捕获到异常,则tx不会回滚。我错过了异常咀嚼的效果,很好。