AbstractRoutingDataSource动态数据源切换

最近遇到这样的一个场景:
1、 先查询oralce 一个表空间的中一个表的数据、作为定时器启动
2、也需要查询oracle另一个表空间的一个表的数据,作为显示数据。
问题点:这两个表空间又没有互相访问的权限。

为了解决这个问题:采用嗯动态切换数据源
按我理解的思路配置:
1、在spring 配置文件配置、数据源1、数据源2
2、在spring 配置文件中 通过一个动态类 把这两个数据源映射,并配置一个默认的数据源
3、把这个动态数据类 映射给hibernate sessionFactory session工厂


1、spring 配置文件中 配置两个数据源、分别是dataSource1和 dataSource2
两个数据源分别配置两个库用户名和密码

<bean name="dataSource1" class="com.alibaba.druid.pool.DruidDataSource"
        init-method="init" destroy-method="close">
        <property name="url" value="${jdbcUrl}" />
        <property name="username" value="${username1}" />
        <property name="password" value="${password1}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="0" />
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="20" />
        <!-- 连接池最大空闲 -->
<!--        <property name="maxIdle" value="20" /> -->
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="0" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000" />
        <property name="validationQuery" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="testWhileIdle" value="true" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="25200000" />
        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="true" />
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="1800" />
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true" />

        <!-- 监控数据库 -->
        <!-- <property name="filters" value="stat" /> -->
        <property name="filters" value="mergeStat" />
    </bean>
    <!-- 配置数据源2 -->
    <bean name="dataSource2" class="com.alibaba.druid.pool.DruidDataSource"
        init-method="init" destroy-method="close">
        <property name="url" value="${jdbcUrl}" />
        <property name="username" value="${username2}" />
        <property name="password" value="${password2}" />
        <!-- 初始化连接大小 -->
        <property name="initialSize" value="0" />
        <!-- 连接池最大使用连接数量 -->
        <property name="maxActive" value="20" />
        <!-- 连接池最大空闲 -->
<!--        <property name="maxIdle" value="20" /> -->
        <!-- 连接池最小空闲 -->
        <property name="minIdle" value="0" />
        <!-- 获取连接最大等待时间 -->
        <property name="maxWait" value="60000" />
        <property name="validationQuery" value="true" />
        <property name="testOnBorrow" value="false" />
        <property name="testOnReturn" value="false" />
        <property name="testWhileIdle" value="true" />
        <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
        <property name="timeBetweenEvictionRunsMillis" value="60000" />
        <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
        <property name="minEvictableIdleTimeMillis" value="25200000" />
        <!-- 打开removeAbandoned功能 -->
        <property name="removeAbandoned" value="true" />
        <!-- 1800秒,也就是30分钟 -->
        <property name="removeAbandonedTimeout" value="1800" />
        <!-- 关闭abanded连接时输出错误日志 -->
        <property name="logAbandoned" value="true" />

        <!-- 监控数据库 -->
        <!-- <property name="filters" value="stat" /> -->
        <property name="filters" value="mergeStat" />
    </bean>

2、 编写spring 配置文件的配置多数源映射关系 -

<bean id="dynamicDataSource" class="com.xxx.core.dataSource.DynamicDataSource" >  
    <property name="targetDataSources">  
        <map key-type="java.lang.String">  
            <entry value-ref="dataSource1" key="dataSource1"></entry>
            <entry value-ref="dataSource2" key="dataSource2"></entry>  
        </map>  
    </property>  
    <property name="defaultTargetDataSource" ref="dataSource1">  
    </property>  
</bean>  

<!-- 配置到hibernate session工厂 -->
    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dynamicDataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.OracleDialect</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="current_session_context_class">org.springframework.orm.hibernate4.SpringSessionContext
                </prop>
            </props>
        </property>
        <!-- 自动扫描hbm方式配置的hibernate文件和.hbm文件 -->
        <property name="mappingLocations">
            <list>
                <value>classpath*:com/xxx/model/*.hbm.xml</value>
            </list>
        </property>
    </bean>

3、自己创建DynamicDataSource
com.xxx.core.dataSource.DynamicDataSource 这个类
DynamicDataSource继承AbstractRoutingDataSource类,并实现了determineCurrentLookupKey()方法。该方法可以实现数据库的动态切换

public class DynamicDataSource extends AbstractRoutingDataSource{
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDataSourceType();//DataSourceContextHolder也需要创建
    }
}

4、自己创建当前线程的变量的工具类DataSourceContextHolder ,用于设置对应的数据源名称:

public class DataSourceContextHolder {  
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();  
    /** 
     * @Description: 设置数据源类型 
     * @param dataSourceType  数据库类型 
     * @return void 
     * @throws 
     */  
    public static void setDataSourceType(String dataSourceType) {  
        contextHolder.set(dataSourceType);  
    }  

    /** 
     * @Description: 获取数据源类型 
     * @param  
     * @return String 
     * @throws 
     */  
    public static String getDataSourceType() {  
        return contextHolder.get();  
    }  

    /** 
     * @Description: 清除数据源类型 
     * @param  
     * @return void 
     * @throws 
     */  
    public static void clearDataSourceType() {  
        contextHolder.remove();  
    }  
}  

以上就完成配置了

5、写个测试方法 看是否生效(思路就是思路就是 切换之后,看是否有对应的表能查出数据
DataSourceContextHolder.setDataSourceType(“dataSource1”);
就可以进行切换数据源,看是否能查出对应数据库表中的数据。

public static void main(String[] args) {
             ApplicationContext ac = new ClassPathXmlApplicationContext(new String[] { "classpath:applicationContext.xml"});
            //指定数据源
                DataSourceContextHolder.setDataSourceType("dataSource1");
            BaseDao baseDao = (BaseDao)ac.getBean("baseDao");
            List list = baseDao.findBySql("select * from table1");

            for(int i=0;i<list.size();i++){
                System.out.println(list.get(i));
            }

            DataSourceContextHolder.setDataSourceType("dataSource2");
            List list2 =baseDao.findBySql(" select *  from table2 t");
            for(int i=0;i<list2.size();i++){
                System.out.println(list2.get(i));
            }
        }

如果没有数据库的事务管理,已经可以实现数据库的动态切换了。但是如果涉及到数据库的事务管理,需要在数据库事务开启切换数据库,
否则数据库的切换只能在下次数据库操作时才生效

https://www.cnblogs.com/softidea/p/7127874.html?utm_source=itdadao&utm_medium=referral
http://blog.csdn.net/u011463444/article/details/72842500
http://blog.csdn.net/gaofuqi/article/details/46417281

猜你喜欢

转载自blog.csdn.net/u010050174/article/details/79307690