1 Reply Latest reply on Jun 15, 2005 3:36 AM by tomerbd2

    DuplicateKeyExecption and primary key generation

    tomerbd2 Newbie

      Hi

      I have 2 Jboss3.2.5 applications servers working in a cluster.
      I'm using for primary key generation The pattern "sequence blocks" taken from the book ejb design patterns.
      However when i have something like 5 threads that are trying to create new entities then i get DuplikateKeyException on the primary key. (with only 1 jboss server not in a cluster everything is fine).
      I was wondering if anybody could help me pin out the problem, following is my code:

      I estimated it might be an Isolation level problem, however i have updated the isolation level to be serializable in that way in mysql ds and the problem still happend...

      <user-name>root</user-name>
       <password></password>
       <TransactionIsolation>TRANSACTION_SERIALIZABLE</TransactionIsolation>
      



      Sequence entity bean

      package messaging_as.domain.util;
      
      import javax.ejb.*;
      
      import messaging_as.util.jmx.ConfigContainer;
      
      abstract public class SequenceBean implements EntityBean {
       EntityContext entityContext;
       public java.lang.String ejbCreate(java.lang.String name) throws CreateException {
       setName(name);
       return null;
       }
       public void ejbPostCreate(java.lang.String name) throws CreateException {
       setSIndex(ConfigContainer.getJMXPropertiesFacade().getSequenceSessionBeanStartIndex());
       }
      
       public void ejbRemove() throws RemoveException {
       }
      
       public abstract void setName(java.lang.String name);
       public abstract void setSIndex(int sIndex);
       public abstract java.lang.String getName();
       public abstract int getSIndex();
       public void ejbLoad() {
       }
      
       public void ejbStore() {
       }
      
       public void ejbActivate() {
       }
      
       public void ejbPassivate() {
       }
      
       public void unsetEntityContext() {
       this.entityContext = null;
       }
       public void setEntityContext(EntityContext entityContext) {
       this.entityContext = entityContext;
       }
       public int getValueAfterIncrementingBy(int blockSize) {
       this.setSIndex(this.getSIndex()+ blockSize);
       return this.getSIndex();
       }
      }
      


      sequence session bean

      package messaging_as.domain.util;
      
      import java.sql.Connection;
      import java.sql.ResultSet;
      import java.sql.SQLException;
      import java.sql.Statement;
      
      import javax.ejb.CreateException;
      import javax.ejb.FinderException;
      import javax.ejb.SessionBean;
      import javax.ejb.SessionContext;
      import javax.naming.Context;
      import javax.naming.NamingException;
      
      import messaging_as.domain.AlbumElementHome;
      import messaging_as.domain.AlbumElementShareHome;
      import messaging_as.domain.UserHome;
      import messaging_as.service.exceptions.InternalException;
      import messaging_as.util.jmx.JMXPropertiesFacade;
      import messaging_as.util.sql.MASConnectionManager;
      
      import org.apache.log4j.Category;
      
      public class SequenceSessionBean implements SessionBean {
       SessionContext sessionContext;
       private Category _log;
       private class Entry {
       Sequence sequence;
       int last;
       };
      
       private java.util.HashMap _entries = new java.util.HashMap();
       private int _blockSize;
       private int _retryCount;
       private SequenceHome _sequenceHome;
      
       public void ejbCreate() throws CreateException {
       _log = Category.getInstance(getClass());
       }
      
       public void ejbRemove() {
      
       }
       public void ejbActivate() {
      
       }
       public void ejbPassivate() {
      
       }
      
       public void setSessionContext(SessionContext sessionContext) {
       this.sessionContext = sessionContext;
       Context namingContext = null;
       try {
       namingContext = new javax.naming.InitialContext();
       _blockSize = JMXPropertiesFacade.getInstance().getSequenceSessionBeanBlockSize();
       _retryCount = JMXPropertiesFacade.getInstance().getSequenceSessionBeanRetryCount();
      
       _sequenceHome = (SequenceHome) namingContext.lookup("SequenceLocalHome");
       }
       catch (NamingException e) {
       _log.error(e.getMessage(), e);
       }
       }
      
       public void synch() throws InternalException {
       Connection connection = null;
       ResultSet resultSet = null;
       Statement statement = null;
       int maxObjectID = 0, maxUID = 0, maxShareID = 0;
       try {
       connection = MASConnectionManager.getInstance().createConnection();
      
       String sql = "select max(" + AlbumElementHome.FIELD_NAME_OBJECT_ID + ") maxObjectID from " + AlbumElementHome.TABLE_NAME;
       statement = connection.createStatement();
       _log.debug("SQL : " + sql);
       statement.execute(sql);
       resultSet = statement.getResultSet();
       if (resultSet.next()) {
       maxObjectID = resultSet.getInt("maxObjectID");
       _log.debug(String.valueOf(maxObjectID));
       }
       resultSet.close();
       statement.close();
       ((Sequence) _sequenceHome.findByPrimaryKey(AlbumElementHome.JNDI_NAME)).setSIndex(maxObjectID + 1);
      
       sql = "select max(" + UserHome.FIELD_UID + ") maxUID from " + UserHome.TABLE_NAME;
       statement = connection.createStatement();
       _log.debug("SQL : " + sql);
       statement.execute(sql);
       resultSet = statement.getResultSet();
       if (resultSet.next()) {
       maxUID = resultSet.getInt("maxUID");
       _log.debug(String.valueOf(maxUID));
       }
       resultSet.close();
       statement.close();
       ((Sequence) _sequenceHome.findByPrimaryKey(UserHome.JNDI_NAME)).setSIndex(maxUID + 1);
      
       sql = "select max(" + AlbumElementShareHome.FIELD_SHARE_ID + ") maxShareID from " + AlbumElementShareHome.TABLE_NAME;
       statement = connection.createStatement();
       _log.debug("SQL : " + sql);
       statement.execute(sql);
       resultSet = statement.getResultSet();
       if (resultSet.next()) {
       maxShareID = resultSet.getInt("maxShareID");
       _log.debug(String.valueOf(maxShareID));
       }
       resultSet.close();
       statement.close();
       ((Sequence) _sequenceHome.findByPrimaryKey(AlbumElementShareHome.JNDI_NAME)).setSIndex(maxShareID + 1);
      
       } catch (SQLException e1) {
       _log.error(e1.getMessage(), e1);
       } catch (FinderException e) {
       throw new InternalException(e);
       } finally {
       try {
       if (connection != null && !connection.isClosed()) connection.close();
       } catch (SQLException e) {
       _log.error(e.getMessage(), e);
       }
       }
      
       }
      
       public int getNextSequenceNumber(String name) {
       try
       {
       Entry entry = (Entry) _entries.get(name);
      
       if (entry == null)
       {
       // add an entry to the sequence table
       entry = new Entry();
       try
       {
       entry.sequence = _sequenceHome.findByPrimaryKey(name);
       }
       catch (javax.ejb.FinderException e)
       {
       _log.info("can't find sequence: " + name + " trying to create it");
       // if we couldn't find it, then create it...
       entry.sequence = _sequenceHome.create(name);
       _log.info("sequence: " + name + " created");
       }
       _entries.put(name, entry);
       }
       if (entry.last % _blockSize == 0)
       {
       for (int retry = 0; true; retry++)
       {
       try
       {
       entry.last = entry.sequence.getValueAfterIncrementingBy(_blockSize);
       break;
       }
       catch (javax.ejb.TransactionRolledbackLocalException e)
       {
       if (retry < _retryCount)
       {
       // we hit a concurrency exception, so try again...
       _log.info("RETRYING");
       continue;
       }
       else
       {
       // we tried too many times, so fail...
       throw new javax.ejb.EJBException(e);
       }
       }
       }
       }
      
       return entry.last++;
       }
       catch (javax.ejb.CreateException e)
       {
       throw new javax.ejb.EJBException(e);
       }
      }
      
      
      }
      


      from ejb-jar.xml

       <container-transaction>
       <method>
       <description />
       <ejb-name>SequenceSession</ejb-name>
       <method-name>getNextSequenceNumber</method-name>
       <method-params>
       <method-param>java.lang.String</method-param>
       </method-params>
       </method>
       <trans-attribute>RequiresNew</trans-attribute>
       </container-transaction>
      


      jboss.xml

       <container-configurations>
       <container-configuration>
       <container-name>Standard CMP 2.x EntityBean with cache invalidation</container-name>
       <commit-option>A</commit-option>
       <cache-invalidation>True</cache-invalidation>
       </container-configuration>
       </container-configurations>
      .
      .
      .
       <entity>
       <ejb-name>Sequence</ejb-name>
       <local-jndi-name>SequenceLocalHome</local-jndi-name>
       <!-- no cache for this entity bean -->
       </entity>
      


      anybody can help with what the problem might be?
      did i update the isolation level correctly?