-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 
Author Message
 Post subject: Container Managed Transaction and ID Generator
PostPosted: Thu Oct 23, 2003 1:35 pm 
Beginner
Beginner

Joined: Tue Oct 07, 2003 12:11 pm
Posts: 32
Location: US
I execute my code in a session bean. So the container manages the transaction.

In my code, I don


Top
 Profile  
 
 Post subject:
PostPosted: Thu Oct 23, 2003 1:56 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
see "session bean hilo generator" on the wiki


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 24, 2003 1:37 pm 
Beginner
Beginner

Joined: Tue Oct 07, 2003 12:11 pm
Posts: 32
Location: US
Hi gavin,

I saw "session bean hilo generator" on the wiki
http://hibernate.org/47.html - let me know if this is the url I should look at.

With that I am writing my own, Session Bean Hi/Lo Generator

but as mentioned in that I couldn't write

Code:
IdentifierGenerator gen = new HiLoGenerator();


as I couldn't find HiLoGenerator so I used

Code:
IdentifierGenerator gen = new TableHiLoGenerator();


at run time, I get an error as method

Code:
public void configure(Type type, Properties params, Dialect d)


was not called in TableHiLoGenerator and in its super class TableGenerator.

as this method is not called, the query member variable in TableGenerator is null. I get errors b'cos of that.

query is initialized in configure()
Do I have to call configure() method or will the API call it and initialize the query

Is there any solution for that? How do I write my
Session Bean Hi/Lo Generator. Please advise.


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 24, 2003 2:04 pm 
Beginner
Beginner

Joined: Tue Oct 07, 2003 12:11 pm
Posts: 32
Location: US
Hi gavin

returnClass is null even for that I think no call made to configure() is the reason.

public static Number get(ResultSet rs, Class clazz) in IdentifierGeneratorFactory throws IdentifierGenerationException, as the class name is null.


Code:
public class TableHiLoGenerator extends TableGenerator {
   
   /**
    * The max_lo parameter
    */
   public static final String MAX_LO = "max_lo";
   
   private long hi;
   private int lo;
   private int maxLo;
   private Class returnClass;
   
   private static final Log log = LogFactory.getLog(TableHiLoGenerator.class);
   
   public void configure(Type type, Properties params, Dialect d) {
      super.configure(type, params, d);
      maxLo = PropertiesHelper.getInt(MAX_LO, params, Short.MAX_VALUE);
      lo = maxLo + 1; // so we "clock over" on the first invocation
      returnClass = type.getReturnedClass();
   }


Top
 Profile  
 
 Post subject:
PostPosted: Fri Oct 24, 2003 4:23 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
You will need to adapt the given Hibernate 1.2 implementation to the current version of Hibernate.


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 4:47 pm 
Beginner
Beginner

Joined: Wed Nov 26, 2003 11:53 am
Posts: 26
Location: Netherlands
Mukund,

I've got the same issue you do: I needed an ID generator so I used the example with the same problems. Currently my code looks like below: I'm still stumped on how to find the Dialect I set up in hibernate.cfg.xml, it still complains that I have to add hibernate.dialect. Apparently Dialect.getDialect() does not use the values from that file. I don't know if calling configure() with each call to next() is right: probably not, but currently I'm just trying to get it to work.

public class HiLoGeneratorBean extends SessionBeanBase
{
private SessionFactory sessionFactory;

// Use the built-in Hibernate hi/lo generator:
TableHiLoGenerator gen = new TableHiLoGenerator();

public Long next() throws HibernateException
{
try
{

gen.configure(Hibernate.LONG, null, Dialect.getDialect());
Session session = getSession();
if (session instanceof SessionImplementor)
{
return (Long) gen.generate((SessionImplementor) session, null);
}
else
{
throw new HibernateException("getSession() did not deliver a SessionImplementor");
}
}
catch (SQLException sqle)
{
throw new HibernateException(sqle);
}
}

private SessionFactory getSessionFactory() throws HibernateException
{
if (sessionFactory == null)
{
sessionFactory = new Configuration().configure().buildSessionFactory();
}

return sessionFactory;
}

private Session getSession() throws HibernateException
{
return getSessionFactory().openSession();
}


Top
 Profile  
 
 Post subject:
PostPosted: Wed Dec 03, 2003 8:50 pm 
Hibernate Team
Hibernate Team

Joined: Tue Aug 26, 2003 12:50 pm
Posts: 5130
Location: Melbourne, Australia
You should call configure once, right after you instantiate the id generator


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2003 6:34 am 
Beginner
Beginner

Joined: Wed Nov 26, 2003 11:53 am
Posts: 26
Location: Netherlands
Below is the version I have now: I get this exception.

Caused by: java.sql.SQLException: You cannot commit with autocommit set!
at org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:494)
at org.jboss.resource.adapter.jdbc.WrappedConnection.commit(WrappedConnection.java:465)
at net.sf.hibernate.id.TableGenerator.generate(TableGenerator.java:126)
at net.sf.hibernate.id.TableHiLoGenerator.generate(TableHiLoGenerator.java:59)
at nl.sogeti.piloot.server.util.HiLoGeneratorBean.next(HiLoGeneratorBean.java:72)

The attempt to add a dummy Properties instance will never work I believe, because TableHiLoGenerator opens a new connection, and it does not get configured, so setting autocommit=false property thingies will never work? As far as I can see, configure() was never intended to be called "from the outside of Hibernate", so you can see I had to do some ugly hacks to try to get things to work (hardcoded dialect, new Properties object).

Code:
TableHiLoGenerator.java:

/// Start of snippet

   public synchronized Serializable generate(SessionImplementor session, Object object)
      throws SQLException, HibernateException {
         
      // This has to be done using a different connection to the
      // containing transaction because the new hi value must
      // remain valid even if the containing transaction rolls
      // back
      Connection conn  = session.getFactory().openConnection();

/// End of snippet


public class HiLoGeneratorBean extends SessionBeanBase
{
   private SessionFactory sessionFactory;

   // Use the built-in Hibernate hi/lo generator:
   TableHiLoGenerator gen = new TableHiLoGenerator();
   
   public HiLoGeneratorBean()
   {
      Dialect dialect = new net.sf.hibernate.dialect.MySQLDialect();
      Properties props = new Properties();
      props.setProperty("hibernate.connection.autocommit", "false");
      gen.configure(Hibernate.LONG, props, dialect);
   }

   /**
    * @ejb.interface-method
    * @ejb.facade-method
    */
   public Long next() throws HibernateException
   {
      try
      {
         Session session = getSession();
         if (session instanceof SessionImplementor)
         {
            Long nextID = null;
            boolean toggleAutoCommit = session.connection().getAutoCommit();
            if (toggleAutoCommit) session.connection().setAutoCommit(false);
            try
            {
               nextID = (Long) gen.generate((SessionImplementor) session, null);
            }
            finally
            {
               if (toggleAutoCommit) session.connection().setAutoCommit(true);
               session.close();
            }
            return nextID;
         }
         else
         {
            throw new HibernateException("getSession() did not deliver a SessionImplementor");
         }
      }
      catch (SQLException sqle)
      {
         throw new HibernateException(sqle);
      }
   }

   private SessionFactory getSessionFactory() throws HibernateException
   {
      if (sessionFactory == null)
      {
         sessionFactory = new Configuration().configure().buildSessionFactory();
      }

      return sessionFactory;
   }

   private Session getSession() throws HibernateException
   {
      return getSessionFactory().openSession();
   }
}
[/code]


Top
 Profile  
 
 Post subject: ...and on a side note...
PostPosted: Fri Dec 05, 2003 7:17 am 
Beginner
Beginner

Joined: Wed Nov 26, 2003 11:53 am
Posts: 26
Location: Netherlands
I read in a post somewhere that for a JDBCTransactionFactory autocommit is set to false by Hibernate. But I'm using a JTATransactionFactory: apparently it sets autocommit to true, since that's what is giving problems. I also read in the MySQL Connector/J docs that autocommit is true by default. If that's so, what is the best place to set autocommit off? In hibernate.cfg.xml (property hibernate.connection.autocommit?), or in case of JBoss, set it in the datasource I'm using?

Code:
<hibernate-configuration>
    <!-- a SessionFactory instance listed as /jndi/name -->
    <session-factory name="java:comp/env/hibernate/PilotusAdminFactory">
        <!-- properties -->
        <property name="hibernate.connection.datasource">java:/PilotusAdminDS</property>
        <property name="hibernate.dialect">net.sf.hibernate.dialect.MySQLDialect</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.use_outer_join">false</property>
        <property name="hibernate.transaction.factory_class">net.sf.hibernate.transaction.JTATransactionFactory</property>
        <property name="hibernate.transaction.manager_lookup_class">net.sf.hibernate.transaction.JBossTransactionManagerLookup</property>
        <property name="jta.UserTransaction">java:/UserTransaction</property>

      <!-- For debugging: remove/set to true in production -->
        <property name="hibernate.cglib.use_reflection_optimizer">false</property>

        <!-- mapping files -->
        <mapping resource="nl/sogeti/piloot/server/admin/model/Authorisation.hbm.xml"/>
        <mapping resource="nl/sogeti/piloot/server/admin/model/Subscription.hbm.xml"/>
        <mapping resource="nl/sogeti/piloot/server/admin/model/Book.hbm.xml"/>
    </session-factory>
</hibernate-configuration>


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2003 10:32 am 
Beginner
Beginner

Joined: Wed Nov 26, 2003 11:53 am
Posts: 26
Location: Netherlands
Greaaattt...

AFAIK, MySQL will only let you turn off autocommit by issuing the SET AUTOCOMMIT=0 command in a SQL script. It is no use setting it in the datasource file, or in the hibernate config file. This means that since I can't do it there, I have to make sure a connection.setAutocommit(false) is called. But since I can't get at the connection (TableHiLoGenerator makes a new one), it's no use calling session.connection().setAutocommit(false).

Sigh.

I think that calling session.commit() in TableHiLoGenerator without checking if a transaction is active or autocommit is on is not right. Methinks that this is something that should be done, even if MySQL is the guilty party here.

Should I enter this in JIRA?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Dec 05, 2003 10:49 am 
Beginner
Beginner

Joined: Wed Nov 26, 2003 11:53 am
Posts: 26
Location: Netherlands
Last ditch effort: setting the transaction attribute from NotSupported to RequiresNew:

Code:
  <assembly-descriptor>
     <container-transaction>
      <method>
         <ejb-name>RA_HiLoGenerator</ejb-name>
          <method-name>*</method-name>
       </method>
       <trans-attribute>RequiresNew</trans-attribute>
    </container-transaction>
  </assembly-descriptor>


And I get this...

Code:
Caused by: java.sql.SQLException: You cannot commit during a managed transaction!
   at org.jboss.resource.adapter.jdbc.BaseWrapperManagedConnection.jdbcCommit(BaseWrapperManagedConnection.java:490)
   at org.jboss.resource.adapter.jdbc.WrappedConnection.commit(WrappedConnection.java:465)
   at net.sf.hibernate.id.TableGenerator.generate(TableGenerator.java:126)
   at net.sf.hibernate.id.TableHiLoGenerator.generate(TableHiLoGenerator.java:59)
   at nl.sogeti.piloot.server.util.HiLoGeneratorBean.next(HiLoGeneratorBean.java:72)
   ... 118 more


So either you have and the call to commit is wrong, or you don't have CMT and the call to commit makes MySQL complain because autocommit is true.


Top
 Profile  
 
 Post subject: ...and finally, a hack for the time being.
PostPosted: Fri Dec 05, 2003 11:31 am 
Beginner
Beginner

Joined: Wed Nov 26, 2003 11:53 am
Posts: 26
Location: Netherlands
...code comes with no warranties ;-)


Code:
public class HiLoGeneratorBean extends DBSessionBeanBase
{
   /**
    * Having these instance variable will work fine even for a
    * stateless session bean. Each instance will have a unique
    * high number, which is fine.
    */
   private int high = 0;
   private int low = 0;

   /**
    * @ejb.interface-method
    * @ejb.facade-method
    */
   public Long next() throws HibernateException
   {
      if (high == 0)
      {
         try
         {
            DataSource ds = getDataSource();
            Connection connection = ds.getConnection();
            //connection.setAutoCommit(false);
            Statement getHighStatement = connection.createStatement();
            getHighStatement.execute("select max(next_hi) from hibernate_unique_key");
            getHighStatement.getResultSet().next();
            high = getHighStatement.getResultSet().getInt(1);
            Statement updateHighStatement = connection.createStatement();
            updateHighStatement.execute("update hibernate_unique_key set next_hi = " + (high + 1) + " where next_hi = " + high);
            connection.close();
         }
         catch (ApplicationException e)
         {
            throw new HibernateException(e);
         }
         catch (SQLException e)
         {
            throw new HibernateException(e);
         }
      }
      
      long next = ((long)high << 32) + low;
      low++;
      
      return new Long(next);
   }

   public DataSource getDataSource() throws ApplicationException
   {
      try
      {
         InitialContext ic = new InitialContext();
         DataSource dataSource = (DataSource) ic.lookup(EjbConstants.JNDI_DATABASE);

         return dataSource;
      }
      catch (NamingException ne)
      {
         throw new ApplicationException(ApplicationExceptionCodes.DATABASE_OPENING_FAILED, log, ne);
      }
   }
}


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 12 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.