Transaction handling in nested method calls

Discussions

EJB design: Transaction handling in nested method calls

  1. Transaction handling in nested method calls (26 messages)

    Hi ,

    I am using stateless session bean. I want to handle transaction in one of the methods in this SSB. Suppose I have a remote interfaced method A which is performing some database operation. uder this method , there is another method B is called which is private under this SSB. This method B is also performing some database changes.
    My constraint is that the whole method A should be sychronized. That means if two users hit the method A at the same time then the method A and method B both should be first executed for user 1 and then release its lock for user 2. currently i m using bean managed transaction. i wrote like as follows:

    MethodA()
    {
    userTransaction ut = getSessionContext.getUserTransaction();
    try
    {
    ut.begin();
    if(some condition)
    {
    //database operation.
    }
    else{
     MethodB(); //method B is called which is privately
                //defined under this SSB.
      }
    ut.commit();
    }catch(Exception e)
    {
    ut.rollBack();
    }

    The problem is that.. method B is being handled for both the user even if the first user does not completed his transaction. i want is that when user1 and user2 hits methodA. This methodA and methodB should be run thoroghly for user1 and then after commit , it should run as a whole for user 2 including the methodB.
    but methodB is not getting locked or synchronized for a particular user and hence i m getting some problem in the database records.

    I have used Container Managed Transaction and used these both methods for Transaction attribute Required, RequiredNew. I have also user Bean Managed Transaction.. but the problem still persists.

    Please Please help me how to get it solved. I am ready to use either CMP or BMP... but i want to get this solved.

    Thanks in advance.

    Threaded Messages (26)

  2. I guess usage of the Isolation level should solve your problem. Use the transaction Isolation level serializable. I am not saying that this is the best option but this is one of the options.
  3. Thanks for your reply.
    but javax.transaction.UserTransaction class does not have any method to define isolation level since it is database dependent also.
    I am using Stateless Session Bean.
    Please tell me how to set this isolation level.
    I tried to set isolation level through Connection.setIsolationLevel(), but nothing happened and problem is still there.
    Can someone tell me that is it even possible that your transaction defined and begin in main method will also handle transaction in sub methods. i think its not possible but i m not sure.
    what should i do.
    please tell me how to solve the same
    Thanks in advance.
  4. If you want method B to be synchronized which is the private method of your bean you can use synchronized keyword, but i am not sure about this because some App server allow these type of operation while others not

    If you want method A to be synchronized which is the businees method of your SSB you can define number of bean instance to be one in your ejb config file in this way you can make sure that there is only one instance of the bean is there which can served only one user at a time, or you can use pessimistic approach but i am not sure that it will work for SSB but in case of entity bean it will work it will lock the records untill the operations on that records are not over this way it will automatically make it synchronized you can set this setting in vendor specific config file
  5. Problem still persists. Please ming the following:

    MethodA {
      
      UserTransaction userTran = getSessionContext().getUserTransaction();
     userTran.begin();
    //some database insertion here.

       subMethodB();

     }
  6. Problem still persists. Please ming the following:

    MethodA {
      
      UserTransaction userTran = getSessionContext
     ().getUserTransaction();
      userTran.begin();
      //some database insertion here.
      
       subMethodB(); //sub method is called.
      
      userTran.commit();

     }

    now when user1 and user2 concerrently hits this method then firstly methodA starts for user1 and when it goes to subMethodB definition, user2 is given the control of methodA. but what i want is user2 should wait until the whole methodA gets completed till userTran.commit();
    but its nothappening.

    My question is now that.. whether it is possible that the transaction will propagate to methodB also. as after facing problem i dont think that transaction is being handeled in sub methods also.

    What i think that transaction can handle one method at a time.no sub methods calling should be there..as in my case transaction is not going in sub methodB and hence locking is not achieved.

    My functional requirement is that methodA and sub methodB will be called and executed till transaction commit statement before any other call is entertained for them.

    someone please tell me this.

    I again repeat that i think transaction is notpossible in this case and i wil have to handle this any other way. isnt it?

    Thanks and regards.
  7. Did you try to make the number of SSB instances to 1
    if you are calling methodB from methodA and if there is a transaction in methodA that transaction will be propagate into methodB unless and until you are not handling it separately in methodB you can verify this thing by making methodB public and define it in remote interface and define transaction on methodA as Requires (New) while on methodB mandatory and invoke methodB from methodA using the remote object
    I believe your problem is not related to the transaction it is something related to the threading which app server you are using
  8. actually I m using WebSphere5.1.x Server and EJB2.0 .
    to get you more clear for this problem i am writing server output lines which i have written in both MethodA and SubMethodB.
    The following output is coming as arranged in order here.
    i handled transaction in methodA which should be propagate to subMethodB. its a Bean Managed Transaction. whether with CMT it is the same as below.

    1. Starting transaction on user1. called methodA.
    2. Starting in subMethodB on user1.
    3. Starting transaction on user2. called methodA.
    4. Startig in subMethodB on user2
    5. Ending in subMethodB on user2
    6. Ending transaction on user2.
    7. Exception caught:xyz.

    so what i want to tell is that.. when in the step2 the user1 is doing in subMethodB it is interrupted and user2 is called up. now user2 is doing all the changes. in database..and goes away leaving user1 in a confusing state. hence i got exception. but despite what the exception is what i want to know is that if i m using transaction then should not it be the case that firstly user1 is given preference to complete the whole cycle till methodA terminates and then only user2 could be given the control of starting methodA. but in this case no of users are fighting in method. so whats the purpose of transaction here then.
    it is not at all providing locking facility . which is my primary aim.
    i ve also done transactionisolation level set to 8 or 1 or 2 or 4 using connection object.
    what should i do using usertransaction so that.. the above output should be such that methodA and methodB will be run for a particular user and no other user can interrupt their process till user1 terminates from the method.
    this is exactly what i want.
    i musing SLSB and methodB is private (i have done it public to using remote interface) and methodA is public remotely called. methodA is calling methodB inside it.

    Now i hope you all got what the problem i m facing and what exactly i want. I ve read over sites that transaction will propagate to sub methods... but i ask it is not AT ALL happening in my case because locking of method is not their.

    or if in the case that transaction doesnt provide lock like i want then what should i do for this lock to occur in my code.

    I m currently using synchronized key word for this. but i dont want to do this thats why fighting for this.


    so please tell me solution for this.
    please tell me in somewhat detail.

    Thanks in advance.
    Mr Sualeh Hasan ..thanks for answering me.. you are again requested to reply me on the above said things.
    and everyone else toooo.

    Awaiting reply. thnaks to all of you.
  9. vishal I believe this is not the problem of transaction but this is the problem of synchronization I think you are doing some db operations which are dependant on the current state of the database let me give you the simple example

    Let say you have a numeric pk in the database and for inserting the new record you are using the max function

    User1 calls methodA and get the max number for the record to be inserted into the db and doing some processing in methodB in a meantime user2 call methodA and he will get the same pk and complete it's transaction before user1 then definitely user1 will get the error

    I believe your case is also similar to this your db operations based upon the current db state

    if this is the case than there are two solution first one is synchronized the methods and the other one is using the read uncommitted isolation level so that you will get changes of uncommitted data but both of these solution are not recommended because in first case you are not using the advantage of pooling and in the second case you are reading the dirty data so it will be better to change the db operations


    Hope this will help you
  10. Hi Sualeh Hasan.

    Thank you very much..as you just shoot the exact description of what problem i am facing currently.
    I appreciate your suggested solutions.
    and i have again 2 questions for it.

    1. If i use synchronization then i think i wont have to user transaction code because synchronization will itself lock the method for me. so am i thinking right ?

    2. II question is that.. i am going to use synchronization at method declaration (i.e., public synchronized methodA) and privat synchronized subMethodB) . so when this will run on websphere server will there be thread level synchronization (As with synchronized(this) statement) or will there be method level synchronization. i want it to be method level synchronization.

    so please answer the above said.
    Thanks once again.

    Vishal
  11. If my memory serves me the EJB specification prohibits synchronization and other thread primitives. In other words you may NOT make the methods synchronized, at least not if you want portable code.

    In addition I don't think that there is a standard way to define transaction isolation for EJB methods. There is usually a non-standard way, though.

    For WebSphere 5 you can select Serializable as "Isolation Level" in the WebSphere extensions part of the EJB deployment descriptor. That should do the job.

    Good luck!
  12. yes that's true according to the j2ee spec you cannot use thread operation in ejbs because that's make code non portable as mentioned by Erik

    But at the same time it depends upon app server as well, most of the servers allowed these type of operations like oracle 9iAs permit IO operation in ejbs which is against the specs

    As far as transaction is concerned it is nothing to deal with synchronization because you use transaction to maintain referential integrity which cannot be achieved through synchronization but I suggest its better to you ejbs transaction instead of using user defined transactions

    if you don't want to change your db logic I believe it will be better to move all the database related code to methodB and make that method synchronized instead of making the methodA synchronized as there is no fixed rule for this type of problems as long as App server is supporting these type of operations. Certainly it is against the j2ee design patterns but who cares :)
  13. Let me tell you what I understood about your suggestion.
    I will move all the code from methodA to subMethodB and use UserTransaction whether CMT or BMT in this methodB.

    but in this way i will have to merge all other methods for other operations in which transaction is supposed to be implemented.

    But i think i should do it. because it s been a long discussion and i think this is the right approach.

    and by using transaction i will also not void j2ee design patterns.

    what do you say.
  14. you cannot apply transaction attribute on private method (methodB)
    what I was saying that use transaction attribute on methodA like requires new or required depending upon your requirement instead of using user managed transaction which you are using currently in your methodA
    if you will use the synchronized keyword for all the business method (like your methodA) then it will effect the application performance and you will not be benefited by the advantages of session bean pooling and other such stuff
    If you are not in a position to modify your database logic then I believe it will be good to move such code to one method and use synchronized keyword there

    hope this will help you
  15. EJB's are distributed by default, so a synchronized doesn't work at all... Here's my 10 cents, if you don't have other choice beside solve this problem inside the bean: try using a singleton as a semaphore, stating if a shared resource is available or not. A simple way would be using a singleton like this: (pls note this won't work in a cluster)

    //A very very simple singleton, depends on Educated Programmer

    public class SharedResource{

    private static SharedResource resource;
    private static boolean available=true;

    protected SharedResource(){}

    public static SharedResource getInstance(){
    if (resource == null) {resource = new SharedResource();}
    return resource;
    }

    //attention here!
    public synchronized boolean isAvailable(){
       if(available){
          available= false;
          return true;
       }
       return false;
    }

    //attention here: be educated and release it!
    public synchronized void thanksForTheResource(){
       available = true;
    }
    }

    ////////////////////////////////////
    Now let's see your Method...

    MethodA()
    {
    //first user to come here gets resource...
    SharedResource sharedResource = SharedResource.getInstance();
    while( !sharedResource.isAvailable() ){
       //wait "forever"..
       //when isAvailable returns true, we will get out of the loop
    }

    userTransaction ut = getSessionContext.getUserTransaction();
    try
    {
    ut.begin();
    if(some condition)
    {
    //database operation.
    }
    else{

     MethodB(); //method B is called which is privately
                //defined under this SSB.
      }
    ut.commit();
    }catch(Exception e)
    {
    ut.rollBack();
    }
    finally{
    //guess what, we are very educated! :)
    sharedResource.thanksForTheResource();
    }

    } //end of MethodA

    Hope this works..
    Cheers.
  16. Thats another good solution and logical too.
    user2 will have to wait until his sharedResource to get true for him. sounds good. and if i m right it will guarantee that NO two users will be working on a code at the same time. right ?

    one question is WHY this approach will not work in clustered environment.

    I am sorry i did not mention it previously but the application I m working on is the type of web application on which 40,000 users will be working and in real sense 40-60 Concurrent users will be there at a time instance. SO my application will be working in a clustered environment.

    The solution suggested if can not work in clustered environment then I still seek an another solution.
  17. If the solution has to work in a clustered environment you really must follow the spec. Singletons and (non-portable) synchronization primitives work only within a single JVM when they work at all.

    However, you can adapt the pattern with reasonable ease by moving the semaphore to the database. Make methodA transactional (transaction required). MethodB will be part of the same transaction as it is a private internal method, not a "real" EJB method. The first thing you do is to aquire a lock using an update of a single specifc row, for example:

    update semaphore_table set lock_ind = 1 where lock_name = 'methodB';

    The second caller will not be able to do that update before the first caller has committed or rolled back his update of the same row. This really should work in a clustered environment and it follows the standard. You'll pay the penalty of a roundtrip to the database and of course the method calls to A will be served one at a time, but then that is what you wanted.

    The table and column names are of course irrelevant, the important thing is that you synchronize your method calls using a specific database row that is locked during the duration of the transaction.

    Again, good luck :-).

    -Erik
  18. Eric

    I got what you are saying but I did not get how to implement it with concern to my problem. :-(

    Can you please explain in detail how will i implement this semaphore at the database level.

    Thank you.
  19. Well, I'll try. I'm afraid I don't have time to post working code.

    1. Start off by declaring methodA transactional (requires or requires_new) in the deployment descriptor.
    2. Create a new table, for example:

    create table app_locks (
      lock_name varchar2(40) primary key,
      lock_ind number(1) not null
    );

    3. Add a row to lock on:

    insert into app_locks values ('methodA', 0);
    commit;

    4. Modify your code to use the lock:

    MethodA(){
    userTransaction ut = getSessionContext.getUserTransaction();
    try {
      ut.begin();
      acquireLock();
      if(some condition) {
        //database operation.
      } else {
        MethodB();
      }
      releaseLock(); // Not necessary, but nice!
      ut.commit();
    }catch(Exception e) {
      ut.rollBack();
    }

    Where acquireLock and releaseLock both obtain a DataSource and execute the proper SQL:

    update app_locks set lock_ind = 1
      where lock_name = 'methodA';

    The release method should set 0 rather than 1. It is not needed, so if performance is critical you can skip it.

    The first caller will get in and do the update. He will then have a database lock on the row. The second caller will try to do the update and will suspend waiting for the database until the first caller completes or until the transaction times out.

    Hope that made more sense? If you prefer to use an entity bean rather than direct JDBC updates that should work as well, but in my view it simply complicates things.
  20. Oh, I missed one thing. As you have a user transaction inside methodA you don't need to declare the method transactional in the deployment description, the user transaction is of course good enough!

    Though why you would want a user transaction there is beyond me, making methodA transactional should amount to the same thing. But stick with what you are comfortable with, you may have a good reason in the code you haven't posted and it should work just as well.
  21. I dont get why releaseLock method is optional. I think we HAVE TO do it.otherwise user2 will not ever get a chance to run methodA.

    After acquireLock execute, the user1 will set lock_id to 1 and user2 will only get into the methodA until the lock_id for methodA does not become 0. So i think we will have to release this lock after completion of methodA for user1. dont you think so or I did not get what did you want to say ?

    i m writing the algorithm as what i understood is like the method acquireLock will behave like this.

    private boolean acquireLock()
    {

    //check to see if the row is locked in the database or not by checking the lock_id for methodA. if it is 0 then {
           return true. and
           do the database operation to update lock_id to 1 for 'methodA' in the database row.
           }
          else if lock_id is already 1 then return false;

    }


    and the code where i have methodA is like this.


    MethodA(){
    userTransaction ut = getSessionContext.getUserTransaction();
    try {
      ut.begin();

      //mind here
      while(!acquireLock());
      

      if(some condition) {
        //database operation.
      } else {
        MethodB();
      }
      
      // i will forcely set lock_id to 0 so that the acquireLock method can return TRUE and //break the while loop for user2.
      releaseLock(); // Not necessary, but nice!
       
      ut.commit();
    }catch(Exception e) {
      ut.rollBack();
    }


    Did I get what did you want to say or I am going another way. :-(

    Please reply as I think its the solution i m going to implement.

    Thanks .
  22. one more thing i forgot to aske.

    suppose i ve implemeted these things in database and everything is working fine. now imagine the situation that if the server crashes or anything worse happens in between the methodA then what will happen is that database lock will remain on methodA because due to server crash we could not release the lock and when we will restart the server, this methodA can not be ever called by any single user due to it is locked by the database which was not released.

    so how we will overcome this problem if this solution is subjected to be implemented.
  23. I wrote this earlier today, but it has not appeared yet. I'll try again.

    You're missing the point a bit. The database transaction is what protects you, not the values in the database. In other words:

    1. You don't have to (must not!) retry. Either you will be able to do the update and then you have a database lock or else you will suspend waiting for a lock in the database until you get one or until the transaction fails and rolls back with no further action on your part. You will get a SQLException and that's it.

    2. You don't have to release the lock using a method call because it is released by the database when you commit or rollback, which you will always do. My release method simply restored the value in the database and the value is never used. Forget about it, I shouldn't have included it.

    3. You don't have to worry about crashes, that's what a database is all about. If the server crashes while methodA holds the lock you will get a rollback automatically and the lock will be available for another server.

    Nice, isn't it?
  24. hi Erik,

    Oh I think I got you.

    Your mean is when i call the method acquireLock(), the definition of the method will update the lock_id to 1 and user1 is given control in the methodA and when user2 comes suddenly and he will call acquireLock() , the method will not update lock_id for user2 because the update made by user1 has not been commited.
    so user2 has to wait in acquireLock() method and can only update and return from acquireLock() until user1 commits his transaction i.e., completes everything in methodA.

    Is it what you want to say.

    If it is like that then its a great solution.

    And this means there it is nothing to do with the values of lock_id (0 or 1) in the database.. we are just virtually running a query just to obtain database lock.

    Is it so.

    Please reply soon.
    Thank you very much
  25. Hi

    Erik

    You are requested to reply once more against my query thrown in the last message of mine.
    I think it will lead to get a final solution of the problems.

    Thanks in advance.
    Vishal Joshi
  26. Hi ,

    I have finally used Singleton semaphore as my solution and it worked well even in nested method calls.
    Its okay for me because i m not going to use my application in clustered environment.
    Thank you to Eril and Hasan.
    I appreciate your comments and solutions to my problem.

    Thanks once again.
  27. Hello,

    I am using EJB3.0 as model and mysql as database. in the case of an entity POJO which is mapped to database, i have to use annotation like @Id(generate=GenerateType.AUTO) to tell thedatabase that the this field should be incremented automatically in the case of record insertion. It works fine. But What should i do in the case i am using Oracle because if I deploy this POJO in Oracle db then the corresponding field is not set as an auto incremented field in the backend. someone said me that i should use generate type as SEQUENCE instead of AUTO. what should i change in the POJO so that it works both in SQL and ORACLE.
    Please reply.
    Thanks in advance.