Hibernate::
|
Hibernate Session Virtualization.Last update: Oct-12-2005 Lets consider this stack: an operating system like GNU-Linux that acts as hardware virtualization layer, and than we put a JVM atop of the OS, and then J2EE has adds another layer of virtualization in the form of EJB- or Web- container, and now we are talking about adding Hibernate Session virtualization. Huh? Sounds like too much of virtualization, doesn't it? Well, sometimes we need it. Lets consider couple of scenarios:
Sometimes it is possible to configure multiple hibernate session factories statically, but sometimes it might be difficult or inefficient. Hibernate provides us with the hook to achieve our goal easier: we can configure just one session factory and then use sessionFactory.getSession( ourConnection ). This will cause Hibernate to create lightweight session object that will operate on the provided connection. The provided connection can be created or borrowed from an appropriate connection pool according to our rules. For example: we could create/reuse connection for the user, or define a database connection based on the current user name, there are no limits. Lets look at the diagram below that depicts a web application that connects every user to its own database.
There is nothing complicated in the approach, its beauty is the simplicity of the implementation. We will simply supply Hibernate with a custom Data Source implementation that is aware of its environment in addition to the initial configuration parameters. public class ContextAwareDSProxy implements DataSource { 16 17 private String dbUrl; 18 private PrintWriter log; 19 private int loginTimeout; 20 21 public void setDriverClassName( String driverClassName ) 22 throws SQLException, ClassNotFoundException, IllegalAccessException, InstantiationException{ 23 DriverManager.registerDriver( ( Driver ) Class.forName( driverClassName).newInstance() ); 24 } 25 26 public void setDbUrl( String dbUrl ){ 27 this.dbUrl = dbUrl; 28 } 29 30 public Connection getConnection() throws SQLException{ 31 if(CallEnv.getUserName() == null && CallEnv.getUserPassword() == null ){ 32 throw new SQLException( "Inappropriate call environment: user name or password is null"); 33 } 34 System.out.println( "Returning connection for::" + CallEnv.getUserName() + " for thread::" + Thread.currentThread() ); 35 return DriverManager.getConnection( dbUrl, CallEnv.getUserName(), CallEnv.getUserPassword()); 36 } 37 38 public Connection getConnection( String string, String string1 ) throws SQLException{ 39 return getConnection( ); 40 } 41 42 public PrintWriter getLogWriter() throws SQLException{ 43 return log; 44 } 45 46 public void setLogWriter( PrintWriter printWriter ) throws SQLException{ 47 log = printWriter; 48 } 49 50 public void setLoginTimeout( int i ) throws SQLException{ 51 loginTimeout = i; 52 } 53 54 public int getLoginTimeout() throws SQLException{ 55 return loginTimeout; 56 } 57 } 58 This particular example returns a connection to the same database based on user credentials, but we could just use user name to construct a different DB URL, or define the necessary DB URL from a mapping of users to databases. That is it, when we run a test client we can see that each thread uses its own database connection.
run-class:
[java] 0 [main] INFO org.springframework.beans.factory.xml.XmlBeanDefinitionReader
- Loading XML bean definitions from class path resource [
com/sourcelabs/hibernate/bhw/vsession/vsession.spring.xml]
[java] 266 [main] INFO org.springframework.context.support.ClassPathXmlApplicationContext
- Bean factory for application context [or
g.springframework.context.support.ClassPathXmlApplicationContext;hashCode=11468767]
: org.springframework.beans.factory.support.DefaultListableBeanFactory defining beans
[propertyConfigurer,dataSource,hSessionFactory,appTxManager,allTxAttrDS,
businessLogicImpl,businessLogic]; root of BeanFactory hierarchy
[java] 284 [main] INFO org.springframework.context.support.ClassPathXmlApplicationContext
- 7 beans defined in applica
tion context [org.springframework.context.support.ClassPathXmlApplicationContext;hashCode=11468767]
[java] 343 [main] INFO org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
- Loading properties fil
e from class path resource [com/sourcelabs/hibernate/bhw/vsession/jdbc.properties]
[java] 351 [main] INFO org.springframework.core.CollectionFactory
- JDK 1.4+ collections available
[java] 373 [main] INFO org.springframework.core.CollectionFactory
- Commons Collections 3.x available
[java] 380 [main] INFO org.springframework.context.support.ClassPathXmlApplicationContext
- Unable to locate MessageSource with name 'messageSource': us
ing default [org.springframework.context.support.DelegatingMessageSource@288051]
[java] 383 [main] INFO org.springframework.context.support.ClassPathXmlApplicationContext
- Unable to locate ApplicationEventMulticaster with name 'applicationEventMulticaster':
using default [org.springframework.context.event.SimpleApplication
EventMulticaster@6cb8]
[java] 384 [main] INFO org.springframework.beans.factory.support.DefaultListableBeanFactory
- Pre-instantiating singletons in factory
[org.springframework.beans.factory.support.DefaultListableBeanFactory
defining beans [propertyConfigurer,dataSource,hSessionFactory,appTxManager,allTxAttrDS,
businessLogicImpl,businessLogic];
root of BeanFactory hierarchy]
[java] 918 [main] INFO org.springframework.orm.hibernate3.LocalSessionFactoryBean
- Building new Hibernate SessionFactory [ja
va] 1045 [main] ERROR org.hibernate.util.JDBCExceptionReporter - Inappropriate call environment:
user name or password is null
[java] 1459 [main] WARN net.sf.ehcache.config.Configurator
- No configuration found. Configuring ehcache from ehcache - failsafe.xml
found in the classpath: jar:file:/home/kosta/.m2/repository/net/sf/ehcache
/ehcache/1.1-1/ehcache-1.1-1.jar!/ehcache-failsafe.xml
[java] 1784 [main] INFO org.springframework.orm.hibernate3.HibernateTransactionManager
- Using DataSource [com.sourcela
bs.hibernate.bhw.vsession.ContextAwareDSProxy@8046f4] of Hibernate SessionFactory
for HibernateTransactionManager
[java] 1811 [main] INFO org.springframework.aop.framework.DefaultAopProxyFactory
- CGLIB2 available: proxyTargetClass f
eature enabled
[java] 1982 [Thread-0] INFO org.springframework.jdbc.datasource.JdbcTransactionObjectSupport
- JDBC 3.0 Savepoint class
is available
[java] Returning connection for::dbuser for thread::Thread[Thread-0,5,main]
[java] Returning connection for::dbuser2 for thread::Thread[Thread-1,5,main]
[java] Returning connection for::dbuser2 for thread::Thread[Thread-1,5,main]
[java] Returning connection for::dbuser for thread::Thread[Thread-0,5,main]
[java] Returning connection for::dbuser2 for thread::Thread[Thread-1,5,main]
[java] Returning connection for::dbuser for thread::Thread[Thread-0,5,main]
[java] Returning connection for::dbuser for thread::Thread[Thread-0,5,main]
[java] Returning connection for::dbuser2 for thread::Thread[Thread-1,5,main]
[java] Returning connection for::dbuser for thread::Thread[Thread-0,5,main]
[java] Returning connection for::dbuser2 for thread::Thread[Thread-1,5,main]
|
© Copyright 2003-2006 SourceLabs, Inc. All Rights Reserved.
411 First Ave S. Ste 403, Seattle, WA 98104 | 206.322.0099 | info@sourcelabs.com