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>
时间: 2024-10-31 10:33:10

Spring+Hibernate实现动态SessionFactory切换的相关文章

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

场景: 1)系统有多个数据库 2)且数据库类型也不尽相同 3)现在应用根据某些条件路由到具体的数据库 4)且在spring+hibernate框架下,支持依赖注入 已有实现,spring动态数据源,但无法实现动态SessionFactory,即不通数据库的方言不一样 目标: 在spring动态数据源的基础上,实现动态SessionFactory 前面写了一篇关于动态切换Hibernate SessionFactory的文章, 原文地址:http://www.cnblogs.com/tangyan

Spring(AbstractRoutingDataSource)实现动态数据源切换

一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中切换数据源,直接把数据写入项目B的数据库中.这种需求,在数据同步与定时任务中经常需要. 那么问题来了,该如何解决多数据源问题呢?不光是要配置多个数据源,还得能灵活动态的切换数据源.以spring+hibernate框架项目为例(引用:http://blog.csdn.net/wangpeng047/article/details/8866239博客的图片): 单个数据源绑定给sessionFacto

Spring(AbstractRoutingDataSource)实现动态数据源切换--转载

原始出处:http://linhongyu.blog.51cto.com/6373370/1615895 一.前言 近期一项目A需实现数据同步到另一项目B数据库中,在不改变B项目的情况下,只好选择项目A中切换数据源,直接把数据写入项目B的数据库中.这种需求,在数据同步与定时任务中经常需要. 那么问题来了,该如何解决多数据源问题呢?不光是要配置多个数据源,还得能灵活动态的切换数据源.以spring+hibernate框架项目为例(引用:http://blog.csdn.net/wangpeng04

spring hibernate实现动态替换表名(分表)

1.概述 其实最简单的办法就是使用原生sql,如 session.createSQLQuery("sql"),或者使用jdbcTemplate.但是项目中已经使用了hql的方式查询,修改起来又累,风险又大!所以,必须找到一种比较好的解决方案,实在不行再改写吧!经过3天的时间的研究,终于找到一种不错的方法,下面讲述之. 2.步骤 2.1 新建hibernate interceptor类 /** * Created by hdwang on 2017/8/7. * * hibernate拦

spring AbstractRoutingDataSource实现动态数据源切换

使用Spring 提供的 AbstractRoutingDataSource 实现 创建 AbstractRoutingDataSource 实现类,负责保存所有数据源与切换数据源策略:public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.ge

spring和hibernate整合时报sessionFactory无法获取默认Bean Validation factory

Hibernate 3.6以上版本在用junit测试时会提示错误: Unable to get the default Bean Validation factory spring和hibernate整合时报sessionFactory无法获取默认Bean Validation factory  ,是因为新版hibernate用到新的jar包造成的,默认会自动找验证包,吴国不需要这一步,可以在spring整合hibernate的配置节点中添加如下标红属性: <bean id="sessio

为什么要用Hibernate框架? 把SessionFactory,Session,Transcational封装成包含crud的工具类并且处理了事务,那不是用不着spring了?

既然用Hibernate框架访问管理持久层,那为何又提到用Spring来管理以及整合Hibernate呢?把SessionFactory,Session,Transcational封装成包含crud的工具类并且处理了事务,那不是用不着spring了? Hibernate操作的步骤如下: 1. 获得Configuration对象 2. 创建SessionFactory 3. 创建Session 4. 打开事务 5. 进行持久化操作.比如上面的添加用户操作 6. 提交事务 7. 发生异常,回滚事务

Spring主从数据库的配置和动态数据源切换原理

原文:https://www.liaoxuefeng.com/article/00151054582348974482c20f7d8431ead5bc32b30354705000 在大型应用程序中,配置主从数据库并使用读写分离是常见的设计模式.在Spring应用程序中,要实现读写分离,最好不要对现有代码进行改动,而是在底层透明地支持. Spring内置了一个AbstractRoutingDataSource,它可以把多个数据源配置成一个Map,然后,根据不同的key返回不同的数据源.因为Abst

spring+hibernate常见异常集合

spring+hibernate出错小结: (1)java.lang.NoClassDefFoundError: org/hibernate/context/CurrentSessionContext 原因:出现这错误时,请更改hibernate的包,更新至最新或3.1以上 (2)java.lang.NoClassDefFoundError: javax/transaction/TransactionManager 原因:缺少jta.jar 或者是找不到hbm.xml文件导致sessionfac