How rollback happens using @Transactional annotaion?

984 views
Skip to first unread message

Ratnadeep Rakshit

unread,
Nov 8, 2014, 2:05:29 PM11/8/14
to play-fr...@googlegroups.com
hello,

BACKGROUND

- I am using PlayFramework v2.3.3 to create a RESTFUL API with JSON payload.
- I use @Transactional for my action methods or any private methods for nested Transactions.
- I am also using Ebean for ORM layer.

QUESTION

How best to rollback a transaction when an error occurs? As my APi is being consumed by mobile clients, I generally send 200OK messages even for failure cases with a error code etc. So, throwing an exception from inside the action method sounds ugly. Do you have any suggestions or sample code for reference?

Thanks for reading.

Sam

Ratnadeep Rakshit

unread,
Nov 9, 2014, 2:20:39 AM11/9/14
to play-fr...@googlegroups.com
Anyone?

Maybe I can demonstrate what I mean :

@Transactional
public static Result someAction(){

    try{
        // Step 1: do some operation with DB
    }catch(SomeCheckedException e){

    }
    // Step 2: call another function from here
    someOtherFunction();
    return reply; // json
}

@Transactional
private static someOtherFunction(){
    // do more with DB
}

What happens when some error happens at Step 1 which I have caught? How can I rollback this transaction? Should I usee Ebean.rollbackTransaction() inside the catch and send back response??

Megazord

unread,
Nov 10, 2014, 8:26:43 AM11/10/14
to play-fr...@googlegroups.com
The @Transactional annotation won't be able to rollback your transaction because you are always returning a success code. I think that you have 2 options:

1. Write your own action composition code to deal with transactions the way you want (that is not complicated and you can get more information in the docs)
2. Change your API behavior to use proper http status code and let the clients handle it (that would be my personal choice)

HTH

Ratnadeep Rakshit

unread,
Nov 11, 2014, 1:44:18 PM11/11/14
to play-fr...@googlegroups.com
Thanks Megazord. So if I take your 2nd suggestion and send respective HTTP status in return instead of ok(), all the transactions or nested transactions will automatically rollback? If so, then I think I would change my API to support various status codes eg. badRequest() etc.

Ratnadeep Rakshit

unread,
Nov 12, 2014, 5:21:57 PM11/12/14
to play-fr...@googlegroups.com
Hi, using the second approach didn't work for me. When I returned 400 status on error, the transaction didn't rollback. Is it something to do with Promise? I am using play Promise and returning a Promise<Result>. I really thought that @Transactional could do the trick. :(



On Monday, 10 November 2014 18:56:43 UTC+5:30, Megazord wrote:

Donovan Muller

unread,
Nov 12, 2014, 11:41:14 PM11/12/14
to play-fr...@googlegroups.com
Hi Ratnadeep,

Play @Transactional  basically implements what Megazord suggested as a first option. I.e. it wraps any composed action in Ebean transaction code. This is the implementation: https://github.com/playframework/playframework/blob/master/framework/src/play-java-ebean/src/main/java/play/db/ebean/TransactionalAction.java
Given that, as per the Ebean docs [http://www.avaje.org/static/javadoc/pub/com/avaje/ebean/Ebean.html#execute(com.avaje.ebean.TxCallable)] your transaction will only rollback if your throw an exception from your action.
You are catching your checked exception and hence why your transaction is not rolling back.
The HTTP status code returned from your action will not affect the state of your transaction at all.

If this is not what you want, as per Magazord's first suggestion, you can write your own action composition to handle transactions. 
See here for an example from the Play docs: https://www.playframework.com/documentation/2.3.x/JavaEbean#Transactional-actions (see the last section on the "traditional approach")

I believe Megazord's second suggestion was that if an exception was caught, that you return an error response code to the client and the client would then have to deal with the consequences.
I.e. Nothing to do with transactionality but more of a design decision.

Cheers

Ratnadeep Rakshit

unread,
Nov 13, 2014, 4:40:06 AM11/13/14
to play-fr...@googlegroups.com
Thank you for your reply Donovan. This is really informative.

I am using the async approach to return response as Promise<Result> from a Controller Action method. Just sharing a sample code below:

Promise<ObjectNode> promiseOfSomething = Promise.promise(new F.Function0<ObjectNode>() {
            public ObjectNode apply() {
                  ObjectNode reply = Json.newObject();
                  try{
                      Ebean.beginTransaction();

                      // business logic here

                      Ebean.commitTransaction();
                  } exception(){

                  } finally {
                      Ebean.endTransaction();
                  }

                  return reply;
            }
});

return promiseOfSomething.map(new Function<ObjectNode, Result>() {
            public Result apply(ObjectNode json) {
                return httpStatus(json); // custom method which return a status based on some code
            }
});

How to make sure that these two blocks run inside a single transaction? I am sorry if this sounds foolish but I couldn't get any documentation on that online.

Any help appreciated.

Sam
Reply all
Reply to author
Forward
0 new messages