3 Replies Latest reply on Dec 20, 2006 1:59 AM by Murtuza Vohra

    Executing Outside Transaction

    Murtuza Vohra Newbie

      Hello,

      I am using JBoss 4.0.5, Eclipse 3.2 on windows XP. MySQL 5.0 as backend.

      I have strange scenario, where in a stateless session bean, i am counting number of times a method A is called as per application requirement. The scenario is put in psuedo code as follows:

      SessionBean1{
      @TransactionAttribute(REQUIRED)
       methodA() throws exception{}
      
      @TransactionAttribute(REQUIRED)
       methodB() throws exception{}
      }
      SessionBean2{
       count(){
       read counter from database and increase counter
       }
      }
      


      The counter must increase even when the methodA() is throws exception. The method execution is:
      methodA() -> count() -> methodB()

      The database changes that occur in all these methods are OK when things go right and all methods are executed sucessfuly. The peoblem occurs when any of the method throws exception. The changes are rolled back including the counter. Is there anyway i can execute count() method outside transaction so the changes in the database are not rolled back.

      I am sure we can set database to read_uncommit but this is not what the rest of the application requires except for count table which is used to store count.

      I'll appreciate your quick response.

      Regards,
      Murtuza

        • 1. Re: Executing Outside Transaction
          jaikiran pai Master

          Try this:

          SessionBean2{
          @TransactionAttribute(NotSupported)
           count(){
           read counter from database and increase counter
           }


          More details at: http://java.sun.com/j2ee/tutorial/1_3-fcs/doc/Transaction3.html


          • 2. Re: Executing Outside Transaction
            Murtuza Vohra Newbie

            I tried your approach, but it does not seems to working in concurrent access to methodA(). Let me explain, I ran test with two threads running almost parallel. Each thread making 100 calls to methodA(). At the end of the test the count should have increased by 200 but its not the case. Its always less than 200. When I looked deeper into the problem I found that two threads calling count() at same time (or before the current thread has written the new counter value to database) will read same counter value from the database. Thus both of them will result in writing same value in the database which is not right. There must be locking mechanism on the table or method which blocks others from access until current thread finishes the count() method. I tried synchronized but in vain.

            I appreciate your help and hope to hear better solution from experts.

            Murtuza

            • 3. Re: Executing Outside Transaction
              Murtuza Vohra Newbie

              I have resolved this problem with @Version attribute. Those who are interested in knowing here is how i did it:

              The counter entity bean is modified as follows:

              @Entity
              @Table(name = "counter")
              public class Counter implements Serializable{
              
               private String counterName;
              
               private long value;
              
               private int version;
              
               @Id
               public String getCounterName() {
               return counterName;
               }
              
               public void setCounterName(String name) {
               this.counterName = name;
               }
              
               public long getValue() {
               return value;
               }
              
               public void setValue(long value) {
               this.value = value;
               }
              
               @Version
               public int getVersion() {
               return version;
               }
              
               public void setVersion(int version) {
               this.version = version;
               }
              }
              


              The update method is modified as follows:

              public long count(){
              
               Counter counter = manager.find(Counter.class, "methodA");
               manager.lock(counter, LockModeType.READ);
               if(counter==null)
               {
               counter = new Counter();
               counter.setCounterName(tableName);
               counter.setValue(1);
               manager.persist(counter);
               }
              
               long returnValue = counter.getValue();
               key.setNextKey(returnValue+1);
               manager.merge(counter);
               manager.flush();
               return returnValue;
              }
              


              Murtuza