前面写了一篇关于动态切换Hibernate SessionFactory的文章,原文地址:http://tangyanbo.iteye.com/admin/blogs/1717402
发现存在一些问题:
需要配置多个HibernateTransactionManager和多个Spring 切面
这样带来两个问题
1. 程序效率降低,因为Spring进行多次Advice的拦截
2. 如果其中一个SessionFactory连接出现问题,会导致整个系统无法工作
今天研究出一种新的方法来解决此类问题
1. 数据源及Hibernate SessionFactory配置:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"> <!-- FOR SqlServer--> <bean id="SqlServer_DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.microsoft.sqlserver.jdbc.SQLServerDriver" /> <property name="url" value="url" /> <property name="username" value="username" /> <property name="password" value="password" /> </bean> <bean id="SqlServer_SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" p:mappingLocations="classpath:/com/entity/*.hbm.xml"> <property name="dataSource" ref="SqlServer_DataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop> <prop key="hibernate.dialect">org.hibernate.dialect.SQLServer2008Dialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> </bean> <!-- FOR Oracle --> <bean id="Oracle _DataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="oracle.jdbc.OracleDriver" /> <property name="url" value="jdbc:oracle:thin:@localhost:1521/orcl" /> <property name="username" value="username" /> <property name="password" value="password" /> </bean> <bean id="Oracle_SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean" p:mappingLocations="classpath:/com/entity/*.hbm.xml"> <property name="dataSource" ref="Oracle_DataSource" /> <property name="hibernateProperties"> <props> <prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop> <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> </props> </property> </bean> </beans>
2. 定义扩展接口DynamicSessionFactoryInf继承SessionFactory
import org.hibernate.SessionFactory; public interface DynamicSessionFactoryInf extends SessionFactory { public SessionFactory getHibernateSessionFactory(); }
3. 定义DynamicSessionFactory实现DynamicSessionFactoryInf
public class DynamicSessionFactory implements DynamicSessionFactoryInf ,ApplicationContextAware{ private static final long serialVersionUID = 1L; private ApplicationContext applicationContext; //动态调用SessionFactory private SessionFactory getHibernateSessionFactory(String name) { return (SessionFactory) applicationContext.getBean(name); } //实现DynamicSessionFactoryInf 接口的方法 public SessionFactory getHibernateSessionFactory() { return getHibernateSessionFactory(ThreadLocalUtil.getCurrentITAsset() .getSessionFactoryName()); } //以下是实现SessionFactory接口的方法,并对当前的SessionFactory实体进行代理 public Reference getReference() throws NamingException { return getHibernateSessionFactory().getReference(); } public Session openSession() throws HibernateException { return getHibernateSessionFactory().openSession(); } public Session openSession(Interceptor interceptor) throws HibernateException { return getHibernateSessionFactory().openSession(interceptor); } public Session openSession(Connection connection) { return getHibernateSessionFactory().openSession(connection); } public Session openSession(Connection connection, Interceptor interceptor) { return getHibernateSessionFactory().openSession(connection,interceptor); } public Session getCurrentSession() throws HibernateException { return getHibernateSessionFactory().getCurrentSession(); } public StatelessSession openStatelessSession() { return getHibernateSessionFactory().openStatelessSession(); } public StatelessSession openStatelessSession(Connection connection) { return getHibernateSessionFactory().openStatelessSession(connection); } public ClassMetadata getClassMetadata(Class entityClass) { return getHibernateSessionFactory().getClassMetadata(entityClass); } public ClassMetadata getClassMetadata(String entityName) { return getHibernateSessionFactory().getClassMetadata(entityName); } public CollectionMetadata getCollectionMetadata(String roleName) { return getHibernateSessionFactory().getCollectionMetadata(roleName); } public Map getAllClassMetadata() { return getHibernateSessionFactory().getAllClassMetadata(); } public Map getAllCollectionMetadata() { return getHibernateSessionFactory().getAllCollectionMetadata(); } public Statistics getStatistics() { return getHibernateSessionFactory().getStatistics(); } public void close() throws HibernateException { getHibernateSessionFactory().close(); } public boolean isClosed() { return getHibernateSessionFactory().isClosed(); } public Cache getCache() { return getHibernateSessionFactory().getCache(); } public void evict(Class persistentClass) throws HibernateException { getHibernateSessionFactory().evict(persistentClass); } public void evict(Class persistentClass, Serializable id) throws HibernateException { getHibernateSessionFactory().evict(persistentClass, id); } public void evictEntity(String entityName) throws HibernateException { getHibernateSessionFactory().evictEntity(entityName); } public void evictEntity(String entityName, Serializable id) throws HibernateException { getHibernateSessionFactory().evictEntity(entityName, id); } public void evictCollection(String roleName) throws HibernateException { getHibernateSessionFactory().evictCollection(roleName); } public void evictCollection(String roleName, Serializable id) throws HibernateException { getHibernateSessionFactory().evictCollection(roleName, id); } public void evictQueries(String cacheRegion) throws HibernateException { getHibernateSessionFactory().evictQueries(cacheRegion); } public void evictQueries() throws HibernateException { getHibernateSessionFactory().evictQueries(); } public Set getDefinedFilterNames() { return getHibernateSessionFactory().getDefinedFilterNames(); } public FilterDefinition getFilterDefinition(String filterName) throws HibernateException { return getHibernateSessionFactory().getFilterDefinition(filterName); } public boolean containsFetchProfileDefinition(String name) { return getHibernateSessionFactory().containsFetchProfileDefinition(name); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
4. 配置动态SessionFactory
<bean id="sessionFactory" class="com.hp.it.qdpadmin.common.DynamicSessionFactory"/>
5. 定义DynamicTransactionManager继承HibernateTransactionManager
public class DynamicTransactionManager extends HibernateTransactionManager { private static final long serialVersionUID = 1047039346475978451L; //重写getDataSource方法,实现动态获取 public DataSource getDataSource() { DataSource sfds = SessionFactoryUtils.getDataSource(getSessionFactory()); return sfds; } //重写getSessionFactory方法,实现动态获取SessionFactory public SessionFactory getSessionFactory() { DynamicSessionFactoryInf dynamicSessionFactory = (DynamicSessionFactoryInf) super .getSessionFactory(); SessionFactory hibernateSessionFactory = dynamicSessionFactory .getHibernateSessionFactory(); return hibernateSessionFactory; } //重写afterPropertiesSet,跳过数据源的初始化等操作 public void afterPropertiesSet() { return; } }
6. 配置dynamicTransactionManager
<bean id="dynamicTransactionManager" class="com.hp.it.qdpadmin.common.DynamicTransactionManager"> <property name="sessionFactory" ref="sessionFactory"/> </bean>
7. 为SessionFactory配置事务切面
<tx:advice id="dynamicTxAdvice" transaction-manager="dynamicTransactionManager"> <tx:attributes> <tx:method name="get*" read-only="true" /> <tx:method name="find*" read-only="true" /> <tx:method name="*" propagation="REQUIRED" rollback-for="Exception" /> </tx:attributes> </tx:advice> <aop:config proxy-target-class="true"> <aop:pointcut id="txPointcut" expression="execution(* com.service.*.*(..))"/> <aop:advisor advice-ref="dynamicTxAdvice" pointcut-ref="txPointcut" /> </aop:config>