2017-04-04 92 views
0

我必须编写一些方法来将值更改到数据库并在文件系统上进行一些操作。 所以我必须做出步序列:春季交易白衣几个操作和回滚

  1. 布尔Updating字段设置为true到数据库中。它用于避免访问与此值链接的文件系统和数据库信息(例如一组汽车)
  2. 对数据库进行一些操作。例如更改日期,名称,值或其他字段。这些更改会影响更多数据库表。
  3. 作任何改动文件系统和数据库
  4. 设置布尔Updating

你可以想象我有管理的错误,并开始回退过程来恢复数据库和文件系统。 我对如何写我的方法有一些疑问。我有:

  • 实体
  • 扩展JpaRepository并具有方法名称查询创建与@Transactional注释@Query如果它们写入到数据库中的资料库界面(否则我recevied错误)
  • 服务接口
  • 包含所有对数据库进行简单更改的方法的服务实现。这个类都被注解@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场是错在这里? 谢谢

+0

我认为你不能保证_FILE RESTORE_阶段,写入文件时抛出异常,很有可能再次写入文件,恢复它的状态也会失败。 – minus

+0

当然,我会尝试只更新一次,如果恢复失败我发送电子邮件并保持文件系统锁定,直到手动操作解决问题。 – luca

回答

1

@Transactional在这里可以。唯一的一点是你需要设置的applicationServices.setUpdating传播到REQUIRES_NEW以便它能够独立地承诺:

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

在例外的情况下,它仍然会只要你在调用setUpdating更新DB最后的块。

+0

谢谢,这个注释创建一个新的事务,暂停主要事务,对吗?因此,如果用'@ Transactional'注解的方法调用具有相同注释的其他方法,那么仅将数据写入数据库的主注释中? – luca

+0

'setUpdating'方法使用一个新的TX而不依赖于调用者方法的事务。如果操作成功,它将提交并且其他TX将会看到数据。 –

+0

完美,而对于问题的第二部分,我是怎么想的? – luca

1

这里有很多问题,其中有些很难理解,这里有一些输入。当你有这个:

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

只有当@Transactional完成后,该标志才会命中数据库。该更改保留在hibernate上下文中,直到方法结束为@Transactionl

所以,当你执行changeDisplacement和其他人来的时候,读取该标志 - 它会看到错误(因为你还没有写入数据库)。你可以通过READ_UNCOMMITTED得到它,但如果你允许的话,这取决于你的应用程序。

您可以使用REQUIRES_NEW的方法,并在那里将该标志设置为true,并在还原时更新该标志。

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

+0

感谢您的建议。是的,setUpdating必须手动还原。在数据库和文件系统之间保持同步是非常困难的,因为在数据库设计时需求是不同的。 – luca