利用AbstractRoutingDataSource实现动态数据源切换 (Spring+Hibernate)

转载之:http://exceptioneye.iteye.com/blog/1698064


Spring配置多数据源的方式和具体使用过程


1、数据源的名称常量类

    public enum DynamicDataSourceGlobal {

Java代码   收藏代码
  1.     ORCL,   
  2.     ISC  
  3. }  
 

2、建立一个获得和设置上下文环境的类,主要负责改变上下文数据源的名称

    public class DynamicDataSourceHolder {

Java代码   收藏代码
  1. // 线程本地环境  
  2. private static final ThreadLocal contextHolder = new ThreadLocal();  
  3.   
  4. // 设置数据源类型  
  5. public static void setDataSourceType(DynamicDataSourceGlobal dataSourceType) {  
  6.     Assert.notNull(dataSourceType, "DataSourceType cannot be null");  
  7.     contextHolder.set(dataSourceType);  
  8. }  
  9.   
  10. // 获取数据源类型  
  11. public static DynamicDataSourceGlobal getDataSourceType() {  
  12.     return (DynamicDataSourceGlobal) contextHolder.get();  
  13. }  
  14.   
  15. // 清除数据源类型  
  16. public static void clearDataSourceType() {  
  17.     contextHolder.remove();  
  18. }  
 

3、建立动态数据源类,注意,这个类必须继承AbstractRoutingDataSource,且实现方法 determineCurrentLookupKey,该方法返回一个Object,一般是返回字符串

    public class DynamicDataSource extends AbstractRoutingDataSource {

Java代码   收藏代码
  1.     @Override  
  2.     protected Object determineCurrentLookupKey() {  
  3.         return DynamicDataSourceHolder.getDataSourceType();  
  4.     }  
  5.   
  6. }  

4、编写spring的配置文件配置多个数据源

     

Java代码   收藏代码
  1.     "parentDataSource"  
  2.         class="org.springframework.jdbc.datasource.DriverManagerDataSource">  
  3.         "driverClass"  
  4.             value="oracle.jdbc.pool.OracleConnectionPoolDataSource" />  
  5.         "url" value="jdbc:oracle:thin:@127.0.0.1:1521:orcl" />  
  6.         "user" value="isc_v10" />  
  7.         "password" value="isc" />  
  8.       
  9.   
  10.       
  11.     "orclDataSource" parent="parentDataSource">  
  12.         "user" value="orcl" />  
  13.         "password" value="orcl" />  
  14.       
  15.   
  16.       
  17.     "iscDataSource" parent="parentDataSource">  
  18.         "user" value="isc_v10" />  
  19.         "password" value="isc" />  
  20.       
  21.   
  22.       
  23.     "dataSource" class="com.wy.config.DynamicDataSource">  
  24.         "targetDataSources">  
  25.             "java.lang.String">  
  26.                 "ORCL" value-ref="orclDataSource">  
  27.                 "ISC" value-ref="iscDataSource">  
  28.               
  29.           
  30.         "defaultTargetDataSource" ref="orclDataSource">  
  31.           
  32.       
  33.   
  34.     "sessionFactory"  
  35.         class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">  
  36.         "dataSource" ref="dataSource" />  
  37.   

 

5、使用

   @Test

Java代码   收藏代码
  1. public void testSave() {  
  2.     // hibernate创建实体  
  3.     DynamicDataSourceHolder.setDataSourceType(DynamicDataSourceGlobal.ORCL);// 设置为另一个数据源  
  4.     com.wy.domain.Test user = new com.wy.domain.Test();  
  5.   
  6.     user.setName("WY");  
  7.     user.setAddress("BJ");  
  8.   
  9.     testDao.save(user);// 使用dao保存实体  
  10.   
  11.     DynamicDataSourceHolder.setDataSourceType(DynamicDataSourceGlobal.ISC);// 设置为另一个数据源  
  12.   
  13.     testDao.save(user);// 使用dao保存实体到另一个库中  
  14.   
  15. }  
  1.        


spring 的AbstractRoutingDataSource解决了这个问题。

原理如图:

利用AbstractRoutingDataSource实现动态数据源切换 (Spring+Hibernate)_第1张图片

 

项目采用的是hibernate,直接在spring.xml设置sessionFactory的dataSource属性为动态数据源即可。

因为项目所有数据库结构都一致,为了避免每次设置数据源的时候要改一堆参数,修改了springAbstractRoutingDataSource类增加了一个getTargetDataSources方法,获取当前数据源详细信息,在其基础上修改数据库名称、用户名、密码即可,不用每次设置一堆参数。

Java代码   收藏代码
  1. Map targetDataSources = dynamicDataSource  
  2.                 .getTargetDataSources();  
  3.         if (targetDataSources == null) {  
  4.             targetDataSources = new HashMap();  
  5.             targetDataSources.put("baseDataSource", baseDataSource);  
  6.         }  
  7.         targetDataSources.put(dataSourceName, subSystemDataSource);  
  8.         dynamicDataSource.setTargetDataSources(targetDataSources);  
  9.         dynamicDataSource.afterPropertiesSet();  
 

另外,设置AbstractRoutingDataSource参数后要调用afterPropertiesSet()方法,spring容器才会进行加载操作。

 

在动态设置数据源方面,可以通过两种方式实现:

  1. 在action(项目使用struts)中进行设置,可以确保在每个servlet线程中数据源是一致的。
  2. 以aop方式,对service方法进行拦截,根据需求设置不同数据源。



你可能感兴趣的:(SSH)