Spring+Hibernate实现动态SessionFactory切换(改进版)

前面写了一篇关于动态切换Hibernate SessionFactory的文章

发现存在一些问题:
需要配置多个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>
原文地址:https://www.cnblogs.com/tangyanbo/p/4282195.html