Spring事务处理了几个opertions和rollback

时间:2017-04-04 09:46:32

标签: java mysql spring transactions rollback

我必须编写一些方法来将值更改为数据库并在文件系统上进行一些操作。 所以我必须做出这一步骤:

  1. 将布尔Updating字段设置为true到数据库中。它用于避免访问与此值链接的文件系统和数据库信息(例如车队)
  2. 对数据库进行一些操作。例如,更改日期,名称,值或其他字段。这些更改会影响更多数据库表。
  3. 更改文件系统和数据库
  4. 将布尔值Updating设置为false
  5. 您可以想象我必须管理错误并启动回滚过程以恢复数据库和文件系统。 我对如何编写我的方法有一些疑问。我有:

    • 实体
    • 扩展JpaRepository并使用方法名称创建查询的存储库接口,如果他们写入数据库,则使用@Query注释@Transactional(否则我收到错误)
    • 服务界面
    • 包含对数据库进行简单更改的所有方法的服务实现。此类使用@Transactional
    • 进行注释

    从其他类我调用服务方法来使用数据库,但如果我调用其中一些方法,我会将每个值写入数据库,因此不可能抛出回滚,或者我错了? 步骤1必须立即写入数据库而不是其他更改应该使用@Transactional属性,但只是将@Transactional添加到我的方法就足够了?对于文件系统回滚,我创建所有子文件夹的备份,并在出现错误时将其还原。 例如:

    @Transactional(rollbackFor=FileSystemException.class)
    private void changeDisplacement(int idApplication, int idDisplacement){
        applicationServices.setUpdating(true); //this has be to write immediatly into database so that the other methods can stop using this application
        Application application = applicationServices.getId(idApplication);
        application.setDisplacement(displacementServices.getId(idDisplacement));
    
        //OTHER OPERATIONS ON DIFFERENT TABLES
    
        //OPERATIONS ON FILE SYSTEM CATCHING ALL EXCEPTION WITH TRY-CATCH AND IN THE CATCH RESTORE FILESYSTEM AND THROW FileSystemException to start database rollback
        //In the finally clause use applicationServices.setUpdating(false)  
    }
    

    是否可以使用此逻辑或此处@Transactional字段有误? 谢谢

2 个答案:

答案 0 :(得分:1)

这里有很多问题,其中一些很难掌握,这里有一些输入。如果你有这个:

@Transactional(rollbackFor=FileSystemException.class)
private void changeDisplacement(int idApplication, int idDisplacement){
    applicationServices.setUpdating(true);

仅当@Transactional完成时,该标志才会到达数据库。更改将保留在hibernate上下文中,直到@Transactionl方法结束。

因此,当您执行changeDisplacement并且其他人来并读取该标志时 - 它将看到错误(因为您尚未将其写入数据库)。您可以通过READ_UNCOMMITTED获取它,但如果您允许,则由您的应用程序决定。

你可以使用REQUIRES_NEW的方法,并在那里将该标志设置为true,并且如果还原更新,则标记为。

通常更新数据库和文件系统并不容易(保持同步)。我之前完成它的方式(可能是更好的选项)是注册事件(一旦创建了正确的数据库),然后写入文件系统。

答案 1 :(得分:1)

@Transactional在这里没问题。唯一需要设置applicationServices.setUpdatingREQUIRES_NEW的传播,以便它可以单独提交:

public class ApplicationServices {
    @Transactional(propagation=Propagation.REQUIRES_NEW)
    public void setUpdating(boolean b) {
        // update DB here
    }
}

如果是异常,只要您在finally块中调用setUpdating,它仍会更新数据库。