1

I create a scheduler that in the same transaction delete rows in DB and insert new rows after delete. But if the adding of rows fails, I lost my data because the delete was correctly. How I can delete and add with the same transaction to avoid losing data in case of errors? I want to do a delete and two different adds in the same table.

Simone Sorgon
  • 155
  • 1
  • 14

1 Answers1

2

There are three cases:

  1. If your code were everything starts is in a method a LocalServiceImpl class generated by service builder:

    • Liferay automatically creates a transaction that begins in the first method called in the first LocalServiceImpl and is propagated in the internal calls that that method does to the methods other LocalServiceImpl classes.
    • So the idea is to have a entry point in a LocalServiceImpl method where Liferay will automatically start the transaction, and from that method, call the other LocalServiceImpl methods that must be executed in the same transaction.
    • Note: by default only the methods that change data (add, update, delete) are creating a new transaction.
  2. If your code is in a MVCActionCommand, you can use the BaseTransactionalMVCActionCommand as the parent class and implement your code in the doTransactionalCommand method.

  3. If your code is outside of the LocalServiceImpl classes, you can always manually create a transaction using TransactionInvokerUtil:

     import com.liferay.portal.kernel.transaction.*;
     import com.liferay.portal.kernel.service.*;
     import java.util.concurrent.*;
    
     private _invokeTransactionally(Callable callable)
         throws Throwable {
    
         Class<?>[] rollbackForClasses = new Class<?>[1];
    
         rollbackForClasses[0]=Exception.class;
    
         try {
             TransactionInvokerUtil.invoke(
                 TransactionConfig.Factory.create(
                     Propagation.REQUIRED, rollbackForClasses), callable);
         }
         catch(Exception e) {
              // handle the exception
         }
     }
    
     Callable callable = new Callable<Void>() {
         Void call() throws Exception {
              // here insert your code
    
              return null;
         }
     }
    
    • Your code should go inside the Callable class.
    • To execute it: _invokeTransactionally(callable);
jorgediaz-lr
  • 942
  • 6
  • 13
  • But the methods in LocalServiceImpl don't have to be private ? Because i create one method that inside there are calls to three private method (delete,add,add).. but if the delete it's ok, and first add no, i lost any data in database.. – Simone Sorgon Apr 22 '21 at 07:14
  • You are free in your choice of parameters - e.g. you can create one `*LocalServiceImpl` method like `updateData(List addTheseObjects, List deleteTheseObjects)` and implement this method as a loop through the objects. `updateData` will open the transaction, and it will be propagated to the following `add` and `delete` calls within `updateData's` implementation (until you return from `updateData`. – Olaf Kock Apr 22 '21 at 07:52
  • My ancient memory says that transactions are opened automatically based on method names - can you confirm or deny, @Jorge? (e.g. `add*`, `update*`, `delete*` would be candidates, while `doSomething()`isn't) – Olaf Kock Apr 22 '21 at 08:04
  • 1
    Yes, thats true, @OlafKock, by default add*, update* and delete* are considered transactional. I think that other methods are annotated with the `@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)` annotation, so they only use the transaction if it is already created in the parent one, but they don't create a new one, as readOnly is true – jorgediaz-lr Apr 22 '21 at 09:28
  • I create method `public void updateContacts(List users,List contacts)` that inside call three methods to (delete, add, add) but if first add isn't ok, i lost the date because delete it was ok – Simone Sorgon Apr 22 '21 at 13:23
  • Method delete it jus a for to delete all concacts. Methods add to add different type of contacts – Simone Sorgon Apr 22 '21 at 13:24