RE: Transaction management without using service builder

Matthew K., modified 6 Years ago. Junior Member Posts: 74 Join Date: 8/31/15 Recent Posts

Hello!

I know that Liferay supports transactions (and a proper rollback mechanism) when using the service builder. But using the service builder everytime I make multiple Liferay api calls in a row feels kind of overkill to me. So I want to ask you if there is another, maybe more compact way to put several api calls in one transaction.

thumbnail
David H Nebinger, modified 6 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts

Sure.

You just create an orchestrating method in the SB tier.

Say, for example, that you are saving 3 different entities, you could create a method saveAll() that invokes the individual saves.  As long as the method follows the standard naming conventions, the transaction will be bound to, as in this example, saveAll().  On exit of saveAll(), it will either commit or roll back depending upon the outcome.

Matthew K., modified 6 Years ago. Junior Member Posts: 74 Join Date: 8/31/15 Recent Posts

Can you please elaborate on your answer? Currently I have no idea what I should do.

What are standard naming conventions for example?

thumbnail
David H Nebinger, modified 6 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts

Transactions are bound automatically to SB methods.  Those starting with "save", "update", "delete", "add" and other action prefixes are bound with write transactions, but "get", "find" and other non-action prefixes get read-only transactions.

 

From an orchestration perspective, let's do an example.  You have student, teacher, class and room.  You are building the scheduling component, so you want to create a class, assign to a room and assign a teacher.

 

Your individual entity methods will have addClass(), probably an assignClassToRoom() and assignTeacherToClass() methods, but calling those externally may lead to a fault if one of the assign methods failed.

 

So if you created a method in your ClassLocalServiceImpl to addClassWithRoomAndTeacher(), you can then orchestrate the calls to addClass(), assignClassToRoom() and assignTeacherToClass() within the context of a single transaction.  With that in place, any failure on the orchestrated method(s) would trigger a rollback across the transaction.

Matthew K., modified 6 Years ago. Junior Member Posts: 74 Join Date: 8/31/15 Recent Posts
With "SB" you probably mean Service Builder, right? Maybe you haven't fully understood my problem, but I want to have a solution without using the service builder of Liferay.
thumbnail
Olaf Kock, modified 6 Years ago. Liferay Legend Posts: 6441 Join Date: 9/23/08 Recent Posts
Matthew K.:
With "SB" you probably mean Service Builder, right? Maybe you haven't fully understood my problem, but I want to have a solution without using the service builder of Liferay.

well, if you go without ServiceBuilder, you can use any other explicit transaction handling method you'd like - you won't get the automated behavior anyway, but that's what you want. There's nothing that limits you, anything you find in the Java world is open for you.

With ServiceBuilder, you can also write your own service, encapsulating other (multiple) servicecalls. This might also be what you're looking for when you talk about overkill for multiple service calls.
 

thumbnail
David H Nebinger, modified 6 Years ago. Liferay Legend Posts: 14933 Join Date: 9/2/06 Recent Posts
Matthew K.:
With "SB" you probably mean Service Builder, right? Maybe you haven't fully understood my problem, but I want to have a solution without using the service builder of Liferay.

No, what you said was you wanted to invoke multiple Liferay APIs within a single transaction scope.

Using SB might seem like overkill, but compared to trying to set up and maintain your own XA transaction around the Liferay calls would actually prove to be overkill because of all of the heavy lifting you'd have to do to make it all happen.
 

thumbnail
Jorge Díaz, modified 6 Years ago. Liferay Master Posts: 753 Join Date: 1/9/14 Recent Posts
Matthew K.:

Hello!

I know that Liferay supports transactions (and a proper rollback mechanism) when using the service builder. But using the service builder everytime I make multiple Liferay api calls in a row feels kind of overkill to me. So I want to ask you if there is another, maybe more compact way to put several api calls in one transaction.


You can create a transaction using TransactionInvokerUtil

 

That util is internally used by Staging process in order to create a transaction during all import operation.

 

Groovy script example:

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;

    TransactionInvokerUtil.invoke(
        TransactionConfig.Factory.create(
            Propagation.REQUIRED, rollbackForClasses), callable);
}

Callable yourLogic = new Callable<Void>() {
    Void call() throws Exception {
        ....your code....
    }
}

_invokeTransactionally(yourLogic);

 

The callable that is passed to TransactionInvokerUtil.invoke is executed in a isolated transaction that will be rolledback in case a Exception specified in rollbackForClasses variable is thrown.

 

Regards,

Jorge Díaz