-->
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.  [ 4 posts ] 
Author Message
 Post subject: WebSphere integration/DataSource/solves a deadlock problem
PostPosted: Mon Jun 14, 2004 4:53 am 
Newbie

Joined: Wed Dec 10, 2003 3:08 am
Posts: 2
Location: Helsinki, Finland
I know that a Hibernate application should use only one Hibernate session in a J2EE transaction (one hibernate session per application transaction). Anyway if you have already built a J2EE application that opens and closes hibernate sessions several times in one J2EE/JTA application transaction, then you should read this posting.

WebSphere 5.0/5.1 gives a different physical database connection for the same transaction if you call DataSource.getConnection() in different SLSB EJBs in some cases (at least when there is concurrent transactions going on). The database doesn't recognize that the different physical database connections belongs to the same transaction. This causes a lot of problems in database transaction isolation. For example, it will cause a deadlock if another EJB modifies some rows and later in the same transaction, another EJB tries to fetch these modified rows. WebSphere will also use different physical database connections for each Hibernate session (in a complex application this might be 10 connections for 1 transaction!).

Read this article to understand what it means:
http://www.ibm.com/developerworks/websp ... _tang.html
It also has the solution. WebSphere will only return the same physical database connection if you use the WebSphere specific API to fetch the connection from the DataSource. WebSphere will return the same physical database connection if the contents of JDBCConnectionSpec objects match (It compares the new connection's JDBCConnectionSpec to the one of the existing connection.).

example code for fetching the JDBC Connection:
Code:
   JDBCConnectionSpec connSpec = WSRRAFactory.createJDBCConnectionSpec();
   connSpec.setTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
   if (user != null || pass != null) {
      connSpec.setUserName(user);
      connSpec.setPassword(pass);   
   }
   Connection connection=((WSDataSource)ds).getConnection(connSpec);



The integration to Hibernate is done using the net.sf.hibernate.connection.ConnectionProvider class. The below code is modified from the ConnectionProvider for JNDI (DatasourceConnectionProvider). There is a helper class for setting the transaction isolation level for a certain application Thread.

To use this ConnectionProvider, add this property to hibernate configuration:
<property name="connection.provider_class">net.sf.hibernate.websphere.WSDataSourceConnectionProvider</property>


Source code:

WSDataSourceConnectionProvider class
Code:
package net.sf.hibernate.websphere;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

import net.sf.hibernate.HibernateException;
import net.sf.hibernate.cfg.Environment;
import net.sf.hibernate.connection.ConnectionProvider;
import net.sf.hibernate.util.NamingHelper;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ibm.websphere.rsadapter.JDBCConnectionSpec;
import com.ibm.websphere.rsadapter.WSCallHelper;
import com.ibm.websphere.rsadapter.WSDataSource;
import com.ibm.websphere.rsadapter.WSRRAFactory;
import com.ibm.ws.rsadapter.jdbc.WSJdbcConnection;
import com.ibm.ws.rsadapter.jdbc.WSJdbcUtil;

/**
* ConnectionProvider implementation that implements WSDataSource specific
* Transaction Isolation level settings for the connection.
* Modified from the original DatasourceConnectionProvider class by Lari Hotari
*
*/
public class WSDataSourceConnectionProvider implements ConnectionProvider {
   private WSDataSource ds;
   private String user;
   private String pass;

   private static final Log log =
      LogFactory.getLog(WSDataSourceConnectionProvider.class);

   public void configure(Properties props) throws HibernateException {

      String jndiName = props.getProperty(Environment.DATASOURCE);
      if (jndiName == null) {
         String msg =
            "datasource JNDI name was not specified by property "
               + Environment.DATASOURCE;
         log.fatal(msg);
         throw new HibernateException(msg);
      }

      user = props.getProperty(Environment.USER);
      pass = props.getProperty(Environment.PASS);

      try {
         ds =
            (WSDataSource) NamingHelper.getInitialContext(props).lookup(
               jndiName);
      } catch (Exception e) {
         log.fatal("Could not find datasource: " + jndiName, e);
         throw new HibernateException("Could not find datasource", e);
      }
      if (ds == null)
         throw new HibernateException(
            "Could not find datasource: " + jndiName);
      log.info("Using datasource: " + jndiName);
   }

   public Connection getConnection() throws SQLException {
      if (log.isDebugEnabled()) {
         log.debug("getConnection()");
      }
      Connection connection=ds.getConnection(createJDBCConnectionSpec());
      
      if(log.isDebugEnabled()) {
         if(connection != null) {
            log.debug("Returning connection, System.identityHashCode=" + System.identityHashCode(connection));
            log.debug("Connection=" + connection);
            log.debug("Shareable=" + WSCallHelper.isShareable(connection));
            log.debug("Class=" + connection.getClass());
            Connection nativeConnection=(Connection)WSJdbcUtil.getNativeConnection((WSJdbcConnection)connection);
            log.debug("Native connection=" + nativeConnection);
            log.debug("Native connection, System.identityHashCode=" + System.identityHashCode(nativeConnection) + ", class=" + nativeConnection.getClass());
         } else {
            log.debug("Returning null");
         }
      }
      return connection;
   }

   public void closeConnection(Connection conn) throws SQLException {
      conn.close();
   }

   public void close() {
   }

   protected JDBCConnectionSpec createJDBCConnectionSpec() {
      JDBCConnectionSpec connSpec = WSRRAFactory.createJDBCConnectionSpec();
      connSpec.setTransactionIsolation(getIsolationLevel());
      if (user != null || pass != null) {
         connSpec.setUserName(user);
         connSpec.setPassword(pass);   
      }
      return connSpec;
   }

   /**
    * @return
    */
   private int getIsolationLevel() {
      int isolationLevel=WSDataSourceInterceptorThreadLocal.getIsolationLevel();
      if(isolationLevel==-1) {
         isolationLevel=Connection.TRANSACTION_READ_COMMITTED;
      }
      if(log.isDebugEnabled()) {
         log.debug("isolationLevel=" + isolationLevel);
      }
      return isolationLevel;
   }
}


Helper class for setting the transaction isolation level.
Code:
package net.sf.hibernate.websphere;


/**
* This class stores desired transaction isolation level in a thread local variable.
*
* @author Lari Hotari
*/
public class WSDataSourceInterceptorThreadLocal extends ThreadLocal {

   public static int getIsolationLevel() {
      Integer intValue=(Integer)threadInstance.get();
      if(intValue != null) {
         return intValue.intValue();
      } else {
         return -1;
      }
   }

   public static void setIsolationLevel(int isolationLevel) {
      threadInstance.set(new Integer(isolationLevel));
   }

   private static ThreadLocal threadInstance = new ThreadLocal() {
      protected Object initialValue() {
         return new Integer(-1);
      }
   };
   
   public static void clear() {
      threadInstance.set(null);
   }

}


Top
 Profile  
 
 Post subject:
PostPosted: Mon Jun 14, 2004 5:32 am 
Hibernate Team
Hibernate Team

Joined: Tue Sep 09, 2003 2:10 pm
Posts: 3246
Location: Passau, Germany
Thanks for documenting that, sounds like a really weird thing to me :)

It would be great if you could at this to the Wiki Community Page on the hibernate hompeage, it will just get lost here in the forum.


Top
 Profile  
 
 Post subject: Link to Wiki
PostPosted: Mon Jun 14, 2004 6:04 am 
Newbie

Joined: Wed Dec 10, 2003 3:08 am
Posts: 2
Location: Helsinki, Finland
This posting is also in the wiki now:
http://www.hibernate.org/204.html


Top
 Profile  
 
 Post subject: WAS Datasource Connection
PostPosted: Tue Apr 29, 2008 11:31 am 
Beginner
Beginner

Joined: Wed Aug 09, 2006 12:09 pm
Posts: 20
Location: Belgium
Hello. I am interested in what you are doing here, using a WAS datasource.

I have looked at the code but this connection.provider_class, does this replace anything in my Hibernate configuration?

The reason I ask is that the class WSDataSourceConnectionProvider, the configure method, accepts arguments of username and password that are taken from the Properties props file.

Now where I am confused is looking at this I do not think I would call it directly but just adding eht connection.provider_class to my Hibernate config will call this WSDataSourceConnectionProvider.

So does the Properties props come from my hibernate.cfg.xml (or hibernate.cfg.Configuration call) meaning that I would still need to define the username, password in my configuration?

Or is this overriding the standard call to hibernate.cfg.Configuration class and I could now do this

Code:
Configuration cfg = new Configuration();
cfg.configure("path/to/my/hibernate.cfg.xml");



And that would then be using the WSDataSourceConnectionProvider class?

Sorry if these questions seem a little dumb I am just not 100% sure about how to implement this.

Thanks for reading.

cheers
Martin


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.