6 Replies Latest reply on Apr 16, 2004 3:49 AM by nraghuram

    NoSuchObjectLocalException

    jchang

      Hello everybody,

      I have two threads executing a findby.... method (from an entity bean) almost at the same time in a STATELESS session bean but one of them is deleting a record in the database. Thus, the other one complains with the following error:

      javax.ejb.NoSuchObjectLocalException: Entity not found: primaryKey=11e1813-fbd1ae2521-b88d8e8d57a53bc420279153d2e46f6f
      at org.jboss.ejb.plugins.AbstractTxInterceptor.invokeNext(AbstractTxInterceptor.java:158)
      at org.jboss.ejb.plugins.TxInterceptorCMT.runWithTransactions(TxInterceptorCMT.java:243)
      at org.jboss.ejb.plugins.TxInterceptorCMT.invoke(TxInterceptorCMT.java:104)
      at org.jboss.ejb.plugins.SecurityInterceptor.invoke(SecurityInterceptor.java:117)
      at org.jboss.ejb.plugins.LogInterceptor.invoke(LogInterceptor.java:191)
      ...

      I have declared all my finder methods from the entity bean and the method that calls these finders in the STATELESS session bean to be transaction type "Required" and NOT read only.

      I thought that if a method is not read-only then only one thread can execute at one time (Transaction locking).

      How can I accomplish that?

      Thanks in advance,

      jchang
      By the way, I am using JBoss 3.2.1 and EJB 2.0

        • 1. Re: NoSuchObjectLocalException
          chawla1975

          Hi,

          I guess this is valid behaviour as if you have two threads accessing the same entity bean with one deleting the row in the database, the other is bound to recieve the exception. Transaction behavior won't help as its not an exclusive usage of the entity bean instance. Transaction only helps for atomicity of operation.

          Hope this helps

          • 2. Re: NoSuchObjectLocalException
            jchang

            Hello Vikas,

            Thanks for replying.

            I am kind scared that this will be a valid behaviour because if I am executing a findBy.... method that is NOT read-only and has a transaction type "Required" then I better have the lock to do whatever I want with that bean. Nobody can do a findBy... on the same bean unless I am done with it first. Isn't this the appropiate behaviour?

            In the logs, I can see that two different threads are executing the same findBy... method of an entity bean which is kind of scary because if one thread decides to delete the record then the other one will have a primary key that doesn't exist anymore in the database.

            There has to be a way to avoid this confrontation between these two beans.

            How come the second thread is being allow to execute the findBy... method in the first place?

            Thanks in advance,

            jchang

            P.S. Please let me know if I am missing something?

            • 3. Re: NoSuchObjectLocalException
              sesques

              Your problem is not a part of EJB or whatever specification. Having a thread deleting rows while another list the rows is a business problem.

              The whole solution for handling that is a combination of transaction, reentrance and lock mechanism.
              The lock mechanism is not a part of EJB spec, but application servers can do that. You can also write a portable lock mechanism, which is decribed at the location:
              http://www.javaworld.com/javaworld/jw-07-2001/jw-0713-optimism.html

              I hope this helps you.

              • 4. Re: NoSuchObjectLocalException
                jchang

                Hello Sesques.

                I appreciate your help.

                Here is a snippet of code. As you can see, the addAttendance of this STATELESS bean is calling the findAttendance method with an specific memberId and timeSlotId. In the logs, I can see that two threads are calling this method almost at the same time but the first thread get to the deleteAttendance method and remove the record from the db. Meanwhile, the second thread went into a waiting state because the first one is working within a transaction. But when it wakes up, it tries to execute code based on the primary keys that got from the findByMemberAndTimeSlotId method that is part of the findAttendance method.

                I am still confused why the container lets 2 threads execute the findByMemberAndTimeSlotId concurrently the first time.

                By the way, the entity bean has transaction type "Required" and the finder methods are NOT read-only. The only methods that are read-only are the get methods. And the commit-option is A

                /**
                 * @ejb.interface-method
                 *
                 * @ejb.transaction
                 * type="Required"
                 */
                 public void addAttendance(String inConferenceId, String inMemberId, String inGroupId, String inTimeSlotId)
                 {
                 ...code...
                
                 // get the record for the current time slot
                 attendanceMain = findAttendance(inMemberId, inTimeSlotId);
                
                 ...more code...
                
                 // delete the existing attendance record
                 deleteAttendance(attendanceMain);
                
                 ...more code...
                 }
                
                
                 /**
                 * @ejb.interface-method
                 *
                 * @ejb.transaction
                 * type="Required"
                 */
                
                 public AttendanceVO findAttendance(String inMemberId, String inTimeSlotId)
                 {
                 AttendanceVO retval = null;
                 logger.debug("findAttendance invoked");
                 try
                 {
                 AttendanceLocalHome alh = AttendanceUtil.getLocalHome();
                 AttendanceLocal al = alh.findByMemberAndTimeSlotId(inMemberId, inTimeSlotId); //second thread gets into a wait state while the first one is doing transactional process.
                 retval = al.getAttendanceVO(); //pk for attendance is gone at this point, exception get thrown here
                 }
                 catch (FinderException fe)
                 {
                 logger.debug(fe.getMessage());
                 }
                 catch (NamingException ne)
                 {
                 logger.warn(ne.getMessage(),ne);
                 }
                 return retval;
                 }
                
                
                 /**
                 * @ejb.interface-method
                 *
                 * @ejb.transaction
                 * type="Required"
                 */
                 public boolean deleteAttendance(AttendanceVO inAttendance)
                 {
                 boolean retval = false;
                 if (inAttendance != null)
                 {
                 try
                 {
                 AttendanceLocalHome alh = AttendanceUtil.getLocalHome();
                 AttendanceLocal al = alh.findByPrimaryKey(inAttendance.getId());
                 if (al != null)
                 {
                 try
                 {
                 al.remove();
                 retval = true;
                 }
                 catch (RemoveException re)
                 {
                 logger.warn(re.getMessage());
                 }
                 }
                 }
                 catch (FinderException fe)
                 {
                 logger.warn(fe.getMessage());
                 }
                 catch (NamingException ne)
                 {
                 logger.warn(ne.getMessage(),ne);
                 }
                 }
                 return retval;
                 }
                


                Thanks for the help

                jchang


                • 5. Re: NoSuchObjectLocalException
                  sesques

                  Hi,

                  If your session bean is declared as "Container-managed transactions", your problem seems as a JBoss bug.

                  Perhaps try to set transaction-type to Bean, and then create a user transaction within your addAttendance method.

                  The user transaction can be obtain with:

                  try {
                  ctx = new InitialContext();
                  tx = (UserTransaction)ctx.lookup("UserTransaction");
                  tx.begin();
                  ...
                  tx.commit();
                  } catch (Exception e)
                  ...
                  tx.rollback();
                  }
                  
                  ctx.close();
                  


                  I'm not sure you can obtain a transaction with
                  sessionContext.getUserTransaction(); in this case.

                  Good luck ;-)


                  • 6. Re: NoSuchObjectLocalException
                    nraghuram

                    What is your container configuration. Are you using Instance Per Transaction ?? and what is the lock ?

                    Raghu