Discussions

EJB design: Transaction Issues with Stateless Session EJB and DAO Objects.

  1. We have implemented Stateless Session EJBs with DAO (Simple JAVA classes) objects, wherein one of my stateless EJB method calls methods of multiple DAO (say CustomerDAO and OrderDAO).

    First we are saving info in CustomerDAo and then into OrderDAO. While saving info in OrderDAO, if there are any exceptions then i want my transaction to be rolledback completely (i.e. entry in CustomerDAO should not be committed). I have tried to implement this by marking my sessioncontext as setRollbackOnly.

    Right now if there is some problem in OrderDAO then my transaction is committed automatically (if autocommit is set to true). If i set it to false then it is not committed even if there is no error.

    My transaction is specified as Container Managed - Required for all methods. Each of my DAOs are having their own connection object, set to AutoCommit "false". Also after putting connection to AutoCommit "FALSE", ORderDAO locks the corresponding Table.

    Pls. inform any solution or work around for the same.

    If i use Entity EJBs with Local Interface will it be of similar performance as my DAOs.

    Eagerly waiting for any response.

    Thanks & regards,

    Tarun Dewan.
  2. Hi,

    Try to create connection obeject in session bean itself ( if you are using datasource or connection pool find them using jndi) and then pass this connection object to both dao you may have to modify your method signature in dao to contain one extra parameter as connection object).if you use above approch in any exception setRollbackOnly will garuntee the automicity of your transction.

    Cheers,
    Naren
  3. When you invoke the method of an EJB, and, you obtain a JDBC connection from within the context of an EJB method (makes no difference if you get the connection in the EJB code itself or a DAO), then there is no need to pass the connection object from the ejb to the DAO, or, from one DAO to the next. The container managers all of it for you.

    I know first hand because I am using ss EJB's calling DAO objects. I have DAO's calling DAO, all involved in JDBC I/O, and I never pass the connection object as an argument. If anything fails, the container rolls back and there are no data integrity issues.
  4. CMT or BMT[ Go to top ]

    Are you talking about CMT? He is doing BMT. I don't think you can get a connection from EJB context in your code.
  5. Hi,
       The problem is the Connection object you keep in every DAO class. Instead of keeping this at the DAO level, try getting it from the application server Connection Pool and do not handle the commit or rollback at DAO level. Throw exceptions (SQLException in this case) and hanlde them in your session bean. Tnat way your container knows whether to commit or rollback as a whole unit of work.

    Here is the pseudo code...

    //session bean...
    method1()
    {
    try {
        // call CustomerDAO method
             customerDAOMethod1();
        // call OrderDAO method
             orderDAOMethod1();
        }
        catch(Throwable)
       {
        // mark session context to rollback this transaction...
            sessionContext.setRollbackOnly();
       }
    }

    in your CustomerDAO class...
    customerDAOMethod1() throws SQLException
    {
       // get the datasource from the app server's Connection pool using JNDI lookup
       Connection con = initalContext.lookup("jdbc/DATASOURCENAME");
       
       // now do DB operations...
    }

    do the same thing in your OrderDAo class also.

    Since you need the datasources at many methods, you may keep the datasource lookup logic in a utility class. (try using singleton pattern for performance)

    Hope this helps...

    Thanks,
    Malar.
  6. This would not work to achieve the desired objective.
    If there is an exception in orderDAOMethod1()and the customerDAOMethod1()has no problems,then the data in customerDAOMethod1() would be commited in the DB automatically.This would leave the system in an incosistent state.

    what alternatively can be done,on the same lines is,set the autocommit to false.Create the connection objects in the EJB by whatever method u choose to be most efficient,pass the objects to the DAOs. Do all these operations in a single try catch block,if there are no exceptions from both these methods,then only commit them thru their respective connection objects,else if there are exceptions do not commit them and roll back the trancsation.This will solve all the incosistency problems too along with the transcations problems.


    > Hi,
    >    The problem is the Connection object you keep in every DAO class. Instead of keeping this at the DAO level, try getting it from the application server Connection Pool and do not handle the commit or rollback at DAO level. Throw exceptions (SQLException in this case) and hanlde them in your session bean. Tnat way your container knows whether to commit or rollback as a whole unit of work.
    >
    > Here is the pseudo code...
    >
    > //session bean...
    > method1()
    > {
    > try {
    >     // call CustomerDAO method
    >          customerDAOMethod1();
    >     // call OrderDAO method
    >          orderDAOMethod1();
    >     }
    >     catch(Throwable)
    >    {
    >     // mark session context to rollback this transaction...
    >         sessionContext.setRollbackOnly();
    >    }
    > }
    >
    > in your CustomerDAO class...
    > customerDAOMethod1() throws SQLException
    > {
    >    // get the datasource from the app server's Connection pool using JNDI lookup
    >    Connection con = initalContext.lookup("jdbc/DATASOURCENAME");
    >    
    >    // now do DB operations...
    > }
    >
    > do the same thing in your OrderDAo class also.
    >
    > Since you need the datasources at many methods, you may keep the datasource lookup logic in a utility class. (try using singleton pattern for performance)
    >
    > Hope this helps...
    >
    > Thanks,
    > Malar.
  7. Mr MAlarvasan is Correct[ Go to top ]

    In this Context, Mr. Malarvasan is right. BTW, see that your App.Server is configured with JTA enabled.