8 Replies Latest reply on Feb 17, 2008 3:51 PM by tynor

    FlushMode=MANUAL -- not immediately commited to db?

    tynor

      Seam 2.0.0.GA
      Hibernate 3.2.4.sp1
      MySQL 5.0.16

      I am using EJB3/JPA persistence and am having trouble with a manually flushed transaction. Even after a call to em.flush(), the data is not visible to an external db client -- it seems that even though manually flushed, the transaction is not committed until after the outer backing bean action method returns.

      I need to ensure that my pending changes to the db are commited to the db so that I can invoke another application which uses that data from the database -- all before actually returning from the backing bean action.

      I've tried to call em.getTransaction().commit(), but get a runtime error:

      Caused by: javax.faces.el.EvaluationException: java.lang.IllegalStateException: A JTA EntityManager cannot use getTransaction()
      


      Is it possible to commit the transaction without returning from an action method?

      Thanks!

      Report.java:
       @Begin(flushMode=FlushModeType.MANUAL, join=true)
       public void wire() {
       // nop - placeholder function here only to allow manual flushing config
       }
      ...
       public void generate () {
       entityManager.persist(foo);
       entityManager.persist(bar);
      ...
       entityManager.flush();
       log.debug("committed"); <-----------
      


      If I set breakpoint after the flush, I cannot see the new data persisted to the database from an external client until I exit all the way back out of the top level action function (report.generate()).

      Report.page.xml (the page that invokes the backing bean action):
      <?xml version="1.0" encoding="UTF-8"?>
      <page xmlns="http://jboss.com/products/seam/pages"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://jboss.com/products/seam/pages http://jboss.com/products/seam/pages-2.0.xsd">
       <!-- wire up manually flushed transaction for reports -->
       <action execute="#{report.wire}"/>
      </page>
      
      


      persistence.xml:
      <?xml version="1.0" encoding="UTF-8"?>
      <!-- Persistence deployment descriptor for dev profile -->
      <persistence xmlns="http://java.sun.com/xml/ns/persistence"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
       version="1.0">
      
       <persistence-unit name="myproject">
       <provider>org.hibernate.ejb.HibernatePersistence</provider>
       <jta-data-source>java:/myprojectDatasource</jta-data-source>
       <properties>
       <property name="hibernate.hbm2ddl.auto" value="update"/>
       <property name="hibernate.cache.use_query_cache" value="true"/>
       <property name="hibernate.show_sql" value="false"/>
       <property name="jboss.entity.manager.factory.jndi.name" value="java:/myprojectEntityManagerFactory"/>
       </properties>
       </persistence-unit>
      </persistence>
      


      components.xml:
       <persistence:managed-persistence-context name="entityManager"
       auto-create="true"
       persistence-unit-jndi-name="java:/myprojectEntityManagerFactory"
      


      myproject-ds.xml:
      <?xml version="1.0" encoding="UTF-8"?>
      <datasources>
      
       <local-tx-datasource>
       <jndi-name>myprojectDatasource</jndi-name>
       <connection-url>jdbc:mysql:///myproject</connection-url>
       <driver-class>com.mysql.jdbc.Driver</driver-class>
       <user-name>myproject</user-name>
       <password>myproject</password>
       </local-tx-datasource>
      
      </datasources>
      





        • 1. Re: FlushMode=MANUAL -- not immediately commited to db?
          msystems

           


          I am using EJB3/JPA persistence and am having trouble with a manually flushed transaction. Even after a call to em.flush(), the data is not visible to an external db client -- it seems that even though manually flushed, the transaction is not committed until after the outer backing bean action method returns.


          The transaction is commited in the after 'invoke application' phase (by the SeamPhaselistener) - if you're using a Seam-managed transaction (looks like you are using it).


          I've tried to call em.getTransaction().commit(), but get a runtime error:
          Caused by: javax.faces.el.EvaluationException: java.lang.IllegalStateException: A JTA EntityManager
          cannot use getTransaction()
          



          The exception is thrown because you're using a Container-managed transaction (CMT) bean.


          Is it possible to commit the transaction without returning from an action method?


          To my knowledge, no !

          You need to use a bean-managed transaction (BMT) bean if you want to control the transaction - i.e. tx.begin() tx.commit() etc.



          • 2. Re: FlushMode=MANUAL -- not immediately commited to db?
            tynor

             


            You need to use a bean-managed transaction (BMT) bean if you want to control the transaction - i.e. tx.begin() tx.commit() etc.


            As I suspected :). Can you point me to what I need to do to declare bean managed persistence? My backing bean is just a POJO/Seam component - it's not an EJB, so I don't think I can use the javax.ejb's @TransactionManagement (BEAN) annotation.

            The following snippet from the Seam docs hint that it's possible, but I can't find any more detailed docs or examples.

            Seam JavaBean components do not provide declarative transaction demarcation like session beans do. You could manage your transactions manually using the JTA UserTransaction or declaratively using Seam's @Transactional annotation.


            Thanks again!



            • 3. Re: FlushMode=MANUAL -- not immediately commited to db?
              tynor

              Bump...

              Can someone point me at some documentation, or an example of how to

              1) mark a Seam POJO's action method to not be transactional (is it sufficient to add @Transactional(NEVER) annotation?

              2) and then how to start and commit a manual user transaction in a way compatible with an application otherwise using Seam managed transactions?

              Thanks!

              • 4. Re: FlushMode=MANUAL -- not immediately commited to db?

                I've got about the same problem as you ,
                and found the sollution for your part
                handling BMT

                a) components.xml switch of transactions (see seam manual)

                 <core:init debug="@debug@" jndi-pattern="@jndiPattern@" transaction-management-enabled="false"/> <!-- transaction-management-enabled="false" -->
                 <!-- <transaction:no-transaction /> --> <transaction:no-transaction />
                 <core:manager concurrent-request-timeout="500"
                 conversation-timeout="99000000"
                

                b) is use following class i extend to my EJB
                i'm still trying out the code, so any remarks are welcome

                my problem is that after some 300 transactions (5minutes/processing for 1 request) all of a sudden it loses the transaction and whatever I do I'm dead . I'm still trying to solve that one



                
                
                //@Stateless
                //@Startup
                //@Name("BMT")
                //@TransactionManagement(TransactionManagementType.BEAN)
                public class BMT {
                @Logger private Log log;
                //@Scope(ScopeType.APPLICATION)
                static int txncount=0;
                @PersistenceContext (type=EXTENDED) private EntityManager em;//do not use @in em
                //@in em would work just fine if you would call entityManager.joinTransaction()
                // in your method before you use the EntityManager.
                // Of course the @Injected EM will not join the transaction automatically
                // because the transaction is started AFTER injection, when the method is called.
                //
                @Resource private UserTransaction userTransaction;
                public String process(String xml) throws Exception {return null;}
                public String copy(StatementsDB sta) throws Exception {return null;}
                public String txs(String argument,StatementsDB sta) throws Exception
                {boolean rollback=true;
                
                 String result=null;
                 int ier=0;
                 if (txncount<1) {txncount=100;
                 int tmo=this.setSessuionTimeout(30);//do not timeout while operations are active
                 boolean seso=isNewSession();}
                 --txncount;
                 if (!em.isOpen())
                 log.info("Em persitence manager not open any more !!!");
                 try{ em.joinTransaction(); }catch (Exception er)
                 {ER(er,"em join the transaction transaction ");throw(er);} //after practicaly 5 minutes we die here
                
                
                 try{ ier=userTransaction.getStatus(); }catch (Exception er) {ER(er,"get status transaction ");}
                 //set transaction timeout
                 try{ userTransaction.setTransactionTimeout(100000); }catch (Exception er) {ER(er,"transaction timeout ");}
                 if (ier!=6) log.info("Status transaction different "+ier);
                try{
                 try {// what is the ejbcontext ????
                 //EJB userTransaction = EJBContext.getUserTransaction( );//EJBclassical way
                 userTransaction= org.jboss.seam.util.EJB.getEJBContext().getUserTransaction();//EJB
                //SEAMEJB if ( userTransaction.isNoTransaction())//SEAMEJB if(transaction.getStatus() == Status.STATUS_NO_TRANSACTION){
                //SEAMEJB { userTransaction= org.jboss.seam.util.EJB.getEJBContext().getUserTransaction();//SEAMEJB
                //SEAMEJB }
                 userTransaction.begin(); // etc
                 // em.joinTransaction();
                 } catch(Exception er) {ER(er,"Begin transaction");}
                 String res=null;
                 if (argument!=null)
                 res = process(argument);
                 if (sta!=null)
                 res=copy(sta);
                 try {
                 userTransaction.commit(); // etc
                 rollback=false;//all is successful kill any possible rollback
                 result=res;//only if successfull commited the result is passed
                 } catch(Exception er) {ER(er,"Commit transaction");}
                
                 } catch(Exception er) {ER(er,"Transaction");}
                 finally
                 { try {
                //SEAMEJB if (!userTransaction.isCommitted()) {userTransaction.rollback();NewTransaction();}//auto detect commitment
                //SEAMEJB else
                 if (rollback) {userTransaction.rollback();
                 //get a new transaction
                 NewTransaction();//Em.gettransaction not for JTA BMT em.getTransaction();//
                 }
                 } catch (Exception er)
                 { String errmsg=er.getClass().getSimpleName() +" err: "+ er.getMessage();
                 if(errmsg.indexOf("NullPointer")>-1 || errmsg.indexOf("OutOfBounds")>0) log.fatal("[transaction BMT ] Rollback failed "+ errmsg,er);
                 else log.error("[transaction BMT ] Rollback failed "+ errmsg );
                 }
                 }//finaly
                 return result;
                }
                public int setSessuionTimeout(int minutes)
                { if (minutes <1)minutes=1;
                 int tmo=0;
                 try {
                 Object obj =ServletContexts.instance().getRequest();//null?
                 if (obj!=null)obj=ServletContexts.getInstance().getRequest().getSession();
                 if (obj!=null) tmo=ServletContexts.instance().getRequest().getSession().getMaxInactiveInterval();
                 if (obj!=null) ServletContexts.instance().getRequest().getSession().setMaxInactiveInterval(minutes*60);
                 if (obj!=null) return tmo;
                 // int tmo=
                // org.jboss.seam.web.ServletContexts.instance().getRequest().getSession().getMaxInactiveInterval();
                // org.jboss.seam.web.ServletContexts.instance().getRequest().getSession().setMaxInactiveInterval(minutes*60);
                 return minutes;
                 } catch (Exception er)
                 { String errmsg=er.getClass().getSimpleName() +" err: "+ er.getMessage();
                 if(errmsg.indexOf("NullPointer")>-1 || errmsg.indexOf("OutOfBounds")>0) log.fatal("ServletContext error "+ errmsg+" time:"+tmo+"/"+ minutes,er);
                 else log.error("[ServletContext error set timeout "+ errmsg +" time:"+tmo+"/"+ minutes );}
                 return 0;
                }
                
                
                public boolean isNewSession()
                
                { try{
                 Object obj =ServletContexts.instance().getRequest();//null
                
                 if (obj!=null)obj=ServletContexts.instance().getRequest().getSession();
                 if (obj!=null) return ServletContexts.instance().getRequest().getSession().isNew();
                
                // return org.jboss.seam.web.ServletContexts.instance().getRequest().getSession().isNew();
                
                } catch (Exception er)
                { String errmsg=er.getClass().getSimpleName() +" err: "+ er.getMessage();
                if(errmsg.indexOf("NullPointer")>-1 || errmsg.indexOf("OutOfBounds")>0) log.fatal("new session error "+ errmsg,er);
                else log.error("[ServletContext error set timeout "+ errmsg );}
                
                 return true;
                }
                private void NewTransaction()
                {
                 log.error("I urgently want a new transaction, I lost the old one in a rollback");
                 try{
                // em.joinTransaction();//test
                 } catch (Exception er){ER(er,"JOIN TRANSACTION RECOVER ");}
                
                }
                private void ER(Exception er,String mes)
                 {String errmsg=er.getClass().getSimpleName() +" err: "+ er.getMessage();
                 if(errmsg.indexOf("NullPointer")>-1 || errmsg.indexOf("OutOfBounds")>0) log.error(mes+" "+ errmsg,er);
                 else log.error(mes+" "+ errmsg);
                }
                


                It's not essential to do the Join the TXN with em but that way my problem is detected prior to executing my process...



                any comment is welcome of coarse.


                • 5. Re: FlushMode=MANUAL -- not immediately commited to db?
                  pmuir

                  To get the transaction do Transactions.instance() - you need to ask on e.g. an EJB3 forum about how to control transactions inside a CMT.

                  You need to ask on the hibernate forum about why .flush() doesn't commit the transaction if you are curious.

                  • 6. Re: FlushMode=MANUAL -- not immediately commited to db?
                    tynor

                    I posted a "solution" on the new forum:

                    Transactions.instance().commit();
                    Transactions.instance().begin();


                    This works, but I am not confident that this is considered clean and proper. Posting to the EJB3 forum doesnt seem appropriate given that these are "seam managed" transactions and my code is a Seam POJO component not an EJB -- how does the Seam framework expect me to be interacting with the transactions it is starting in its PhaseListener?


                    • 7. Re: FlushMode=MANUAL -- not immediately commited to db?
                      pmuir

                      Thats just fine.

                      They are seam managed but backed by JTA CMT which are EJB3 provided.

                      • 8. Re: FlushMode=MANUAL -- not immediately commited to db?
                        tynor

                        Most excellent! Thanks for putting my mind at ease.