前面寫了一篇關於動態切換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>