英文:
How to force @Transactional in JPA to commit two repository action not only just the last one?
问题
你好,我试图实现的目标是在使用Spring Data JPA和@Transactional注解的情况下执行"UPDATE"操作,然后执行"DELETE"操作,我希望这两个操作都能执行,但如果其中一个操作失败,我需要回滚,我应该如何正确地实现这一点?
首先,这是我的服务类:
@Transactional
@Service
public class TransDeliveryPlanningService {
public ResponseRequest<TransDeliveryPlanning> deleteTransDeliveryPlanning(InputDeleteRequest<ViewAndDeleteRequest> request) {
// ... 你的代码 ...
TransDeliveryPlanning updatedTransDeliveryPlanning = transDeliveryPlanningRepository.save(transDeliveryPlanningOld);
transDeliveryPlanningRepository.delete(transDeliveryPlanningOld);
// ... 你的代码 ...
return response;
}
}
正如你所看到的,我在**transDeliveryPlanningRepository.save
后面执行了transDeliveryPlanningRepository.delete
,然后需要执行的下一个仓库操作是transStuffingRepository.deleteAll
**。
我需要先保存再删除的目的是使用Hibernate Audit Envers来创建AuditLog,所以我希望将删除原因记录到我的审计表中,然后再删除记录。但是当我使用**@Transactional
注解时,transDeliveryPlanningRepository.save
(更新)没有被执行,我的函数只执行了transDeliveryPlanningRepository.delete
和transStuffingRepository.deleteAll
,我如何确保使用@Transactional
**注解时仍然执行保存操作呢?
更新:
根据Morteza Bandi在下面的建议,这是我的更新后的代码:
这是我的仓库:
@Repository
public interface TransDeliveryPlanningRepository extends RevisionRepository<TransDeliveryPlanning, Long, Integer>, JpaRepository<TransDeliveryPlanning, Long> {
@Modifying
TransDeliveryPlanning save(TransDeliveryPlanning transDeliveryPlanning);
}
当我这样做时,仍然没有在删除之前执行更新操作,我还漏掉了什么吗?
英文:
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 :
@Transactional
@Service
public class TransDeliveryPlanningService {
public ResponseRequest<TransDeliveryPlanning> deleteTransDeliveryPlanning(InputDeleteRequest<ViewAndDeleteRequest> request) {
String currentUser = request.getLoggedInUser();
String reasonDeleted = request.getReason();
Long id = request.getObject().getId();
ResponseRequest<TransDeliveryPlanning> response = new ResponseRequest<TransDeliveryPlanning>();
TransDeliveryPlanning transDeliveryPlanningOld = transDeliveryPlanningRepository.findById(id).orElseThrow(() -> new ResourceNotFound("Data "+ id +" not found!"));
transDeliveryPlanningOld.setIsDeleted(true);
transDeliveryPlanningOld.setReasonDeleted(reasonDeleted);
transDeliveryPlanningOld.setModifiedBy(currentUser);
TransDeliveryPlanning updatedTransDeliveryPlanning = transDeliveryPlanningRepository.save(transDeliveryPlanningOld);
transDeliveryPlanningRepository.delete(transDeliveryPlanningOld);
//NOTE delete transStuffing
List<TransStuffing> transStuffing = transStuffingRepository.findBydeliveryPlanningId(transDeliveryPlanningOld.getId());
Boolean deletePermit = false;
for(TransStuffing ts : transStuffing) {
if(ts.getStatus().equalsIgnoreCase("new")) {
deletePermit = true;
} else {
throw new ResourceIsDelete("Stuffing " + ts.getStuffingNo() + " Status already changed, delete is not permited!");
}
}
if(deletePermit){
transStuffingRepository.deleteAll(transStuffing);
}
//NOTE end of delete transStuffing
if(updatedTransDeliveryPlanning != null) {
response.setResponse("Sukses Hapus");
response.setObject(updatedTransDeliveryPlanning);
} else {
response.setResponse("Gagal Hapus");
}
return response;
}
}
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 :
@Repository
public interface TransDeliveryPlanningRepository extends RevisionRepository<TransDeliveryPlanning, Long, Integer>, JpaRepository<TransDeliveryPlanning, Long> {
@Modifying
TransDeliveryPlanning save(TransDeliveryPlanning transDeliveryPlanning);
}
when i do this, still it's not update before delete, what did i still miss here?
答案1
得分: 1
尝试将 @Transactional
放在 service
方法内的一个方法上方。例如:
@Service
public class MyService {
@Autowired
private MyRepo myRepo;
@Autowired
private MyRepo2 myRepo2;
@Transactional
public void yourTransactionService(arguments){
*** 在这里进行您的 DML 操作 ***
例如:
myRepo.save(blabla);
myRepo.delete(blabla1);
...
myRepo2.save(blabla2);
myRepo3.delete(blabla3);
...
}
}
这样,在调用 yourTransactionService(arguments)
时,要么所有的 DML
操作都被持久化,要么它们都不被持久化。
英文:
try putting @Transactional
above a method inside service
method. e.g.:
@Service
public class MyService {
@Autowired
private MyRepo myRepo;
@Autowired
private MyRepo2 myRepo2;
@Transactional
public void yourTransactionService(arguments){
*** your DML operations here ***
e.g.
myRepo.save(blabla);
myRepo.delete(blabla1);
...
myRepo2.save(blabla2);
myRepo3.delete(blabla3);
...
}
}
This way when calling yourTransactionService(arguments)
either all the DML
s 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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论