如何在JPA中强制 @Transactional 在提交两个仓库操作,而不仅仅是最后一个?

huangapple go评论107阅读模式
英文:

How to force @Transactional in JPA to commit two repository action not only just the last one?

问题

你好,我试图实现的目标是在使用Spring Data JPA和@Transactional注解的情况下执行"UPDATE"操作,然后执行"DELETE"操作,我希望这两个操作都能执行,但如果其中一个操作失败,我需要回滚,我应该如何正确地实现这一点?

首先,这是我的服务类:

  1. @Transactional
  2. @Service
  3. public class TransDeliveryPlanningService {
  4. public ResponseRequest<TransDeliveryPlanning> deleteTransDeliveryPlanning(InputDeleteRequest<ViewAndDeleteRequest> request) {
  5. // ... 你的代码 ...
  6. TransDeliveryPlanning updatedTransDeliveryPlanning = transDeliveryPlanningRepository.save(transDeliveryPlanningOld);
  7. transDeliveryPlanningRepository.delete(transDeliveryPlanningOld);
  8. // ... 你的代码 ...
  9. return response;
  10. }
  11. }

正如你所看到的,我在**transDeliveryPlanningRepository.save后面执行了transDeliveryPlanningRepository.delete,然后需要执行的下一个仓库操作是transStuffingRepository.deleteAll**。

我需要先保存再删除的目的是使用Hibernate Audit Envers来创建AuditLog,所以我希望将删除原因记录到我的审计表中,然后再删除记录。但是当我使用**@Transactional注解时,transDeliveryPlanningRepository.save(更新)没有被执行,我的函数只执行了transDeliveryPlanningRepository.deletetransStuffingRepository.deleteAll,我如何确保使用@Transactional**注解时仍然执行保存操作呢?

更新

根据Morteza Bandi在下面的建议,这是我的更新后的代码:
这是我的仓库:

  1. @Repository
  2. public interface TransDeliveryPlanningRepository extends RevisionRepository<TransDeliveryPlanning, Long, Integer>, JpaRepository<TransDeliveryPlanning, Long> {
  3. @Modifying
  4. TransDeliveryPlanning save(TransDeliveryPlanning transDeliveryPlanning);
  5. }

当我这样做时,仍然没有在删除之前执行更新操作,我还漏掉了什么吗?

英文:

Hi what i trying to achieve is to do "UPDATE" action and then do "DELETE" action with Spring Data JPA and @Transactional annotation, and i want both action is executed but if one of the action is failed, i need a rollback, how do i do this properly?

first here is my service class :

  1. @Transactional
  2. @Service
  3. public class TransDeliveryPlanningService {
  4. public ResponseRequest&lt;TransDeliveryPlanning&gt; deleteTransDeliveryPlanning(InputDeleteRequest&lt;ViewAndDeleteRequest&gt; request) {
  5. String currentUser = request.getLoggedInUser();
  6. String reasonDeleted = request.getReason();
  7. Long id = request.getObject().getId();
  8. ResponseRequest&lt;TransDeliveryPlanning&gt; response = new ResponseRequest&lt;TransDeliveryPlanning&gt;();
  9. TransDeliveryPlanning transDeliveryPlanningOld = transDeliveryPlanningRepository.findById(id).orElseThrow(() -&gt; new ResourceNotFound(&quot;Data &quot;+ id +&quot; not found!&quot;));
  10. transDeliveryPlanningOld.setIsDeleted(true);
  11. transDeliveryPlanningOld.setReasonDeleted(reasonDeleted);
  12. transDeliveryPlanningOld.setModifiedBy(currentUser);
  13. TransDeliveryPlanning updatedTransDeliveryPlanning = transDeliveryPlanningRepository.save(transDeliveryPlanningOld);
  14. transDeliveryPlanningRepository.delete(transDeliveryPlanningOld);
  15. //NOTE delete transStuffing
  16. List&lt;TransStuffing&gt; transStuffing = transStuffingRepository.findBydeliveryPlanningId(transDeliveryPlanningOld.getId());
  17. Boolean deletePermit = false;
  18. for(TransStuffing ts : transStuffing) {
  19. if(ts.getStatus().equalsIgnoreCase(&quot;new&quot;)) {
  20. deletePermit = true;
  21. } else {
  22. throw new ResourceIsDelete(&quot;Stuffing &quot; + ts.getStuffingNo() + &quot; Status already changed, delete is not permited!&quot;);
  23. }
  24. }
  25. if(deletePermit){
  26. transStuffingRepository.deleteAll(transStuffing);
  27. }
  28. //NOTE end of delete transStuffing
  29. if(updatedTransDeliveryPlanning != null) {
  30. response.setResponse(&quot;Sukses Hapus&quot;);
  31. response.setObject(updatedTransDeliveryPlanning);
  32. } else {
  33. response.setResponse(&quot;Gagal Hapus&quot;);
  34. }
  35. return response;
  36. }
  37. }

as you can see, i do transDeliveryPlanningRepository.save and then the next line i do transDeliveryPlanningRepository.delete and the next repo i need to execute is transStuffingRepository.deleteAll

The goal i need to do save before delete is i use Hibernate Audit Envers to create an AuditLog, so i want log the delete reason into my audit table and then delete the record. But when i use **@Transactional** annotation the transDeliveryPlanningRepository.save (update) not executed, my function just execute transDeliveryPlanningRepository.delete and transStuffingRepository.deleteAll how i keep the save executed with @Transactional annotation?

UPDATE

As Morteza Bandi answer below suggestion, here is my updated code :
here is my repository :

  1. @Repository
  2. public interface TransDeliveryPlanningRepository extends RevisionRepository&lt;TransDeliveryPlanning, Long, Integer&gt;, JpaRepository&lt;TransDeliveryPlanning, Long&gt; {
  3. @Modifying
  4. TransDeliveryPlanning save(TransDeliveryPlanning transDeliveryPlanning);
  5. }

when i do this, still it's not update before delete, what did i still miss here?

答案1

得分: 1

尝试将 @Transactional 放在 service 方法内的一个方法上方。例如:

  1. @Service
  2. public class MyService {
  3. @Autowired
  4. private MyRepo myRepo;
  5. @Autowired
  6. private MyRepo2 myRepo2;
  7. @Transactional
  8. public void yourTransactionService(arguments){
  9. *** 在这里进行您的 DML 操作 ***
  10. 例如
  11. myRepo.save(blabla);
  12. myRepo.delete(blabla1);
  13. ...
  14. myRepo2.save(blabla2);
  15. myRepo3.delete(blabla3);
  16. ...
  17. }
  18. }

这样,在调用 yourTransactionService(arguments) 时,要么所有的 DML 操作都被持久化,要么它们都不被持久化。

英文:

try putting @Transactional above a method inside service method. e.g.:

  1. @Service
  2. public class MyService {
  3. @Autowired
  4. private MyRepo myRepo;
  5. @Autowired
  6. private MyRepo2 myRepo2;
  7. @Transactional
  8. public void yourTransactionService(arguments){
  9. *** your DML operations here ***
  10. e.g.
  11. myRepo.save(blabla);
  12. myRepo.delete(blabla1);
  13. ...
  14. myRepo2.save(blabla2);
  15. myRepo3.delete(blabla3);
  16. ...
  17. }
  18. }

This way when calling yourTransactionService(arguments) either all the DMLs are persisted or none of them persisted.

答案2

得分: -2

有一种简单的方法可以通过使用查询本身来实现这一点,您可以使用commit、transaction和rollback。

例如:您首先必须启动事务,然后需要将autocommit设置为0,这样每次发生的事务在您确认一切正常后将不会被提交,否则您可以传递一个语句作为回滚,这会将您在启动事务后执行的所有操作都回滚。为了更好地理解这一点,请使用以下[链接] 1

英文:

There is a simple way to do this just by using query itself, you can use commit, transaction and roll back

For ex: you have to start the transaction at first, then you need to set autocommit = 0 so that every transaction that will take place will not get commit once you are ok with everything give commit else you can pass a statement as rollback this rolls back all the operations you have done after starting the transaction. For better understanding this use the following link

huangapple
  • 本文由 发表于 2020年10月13日 16:41:23
  • 转载请务必保留本文链接:https://go.coder-hub.com/64331680.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定