在spring引导应用程序中在事务中包装多个调用?

在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

我在spring应用程序中使用jdbctemplate对db执行查询

下面是用@Transactional注释的方法

@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);
    }
}
  • 插入正确的
  • 插入正确的
  • 插入,但您可以尝试在数字列中插入字符串,或在非空列中插入null
  • 你可以在这里看到更多


    关于返回布尔值,我认为最好抛出一个异常,它将自动回滚事务。

    否!如果捕获到异常,您的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不会回滚。我错过了异常咀嚼的效果,很好。