Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。
基本信息
1、Spring配置多数据源的方式和具体使用过程。
2、Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况:
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。
3、Spring2.x的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。
实现
具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。
一、动态配置多数据源
1. 数据源的名称常量类:
package com.frogking.datasource;
public class DataSourceConst {
public static final String Admin="Admin";
public static final String User = "User";
}
2. 建立一个获得和设置上下文环境的类,主要负责改变上下文数据源的名称:
package com.frogking.datasource;
public class DataSourceContextHolder {
private static final ThreadLocal contextHolder =
new ThreadLocal(); // 线程本地环境
// 设置数据源类型
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
// 获取数据源类型
public static String getDataSourceType() {
return (String) contextHolder.get();
}
// 清除数据源类型
public static void clearDataSourceType () {
contextHolder.remove();
}
}
3. 建立动态数据源类,注意,这个类必须继承AbstractRoutingDataSource,且实现方法determineCurrentLookupKey,该方法返回一个Object,一般是返回字符串:
package com.frogking.datasource;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
// 在进行DAO操作前,通过上下文环境变量,获得数据源的类型
return DataSourceContextHolder. getDataSourceType();
}
}
4. 编写spring的配置文件配置多个数据源
<!-- 数据源相同的内容 -->
<bean class="org.springframework.jdbc.datasource.DriverManagerDataSource" id="parentDataSource">
<property name="driverClassName">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="username">
<value>root</value>
</property>
<property name="password">
<value>1234</value>
</property>
</bean>
<!-- 以下配置各个数据源的特性 -->
<!-- 数据库test -->
<bean parent="parentDataSource" id="adminDataSource">
<property name="url">
<value>jdbc:mysql://localhost:3306/test</value>
</property>
</bean>
<!-- 不同的数据库test2 -->
<bean parent="parentDataSource" id="userDataSource">
<property name="url">
<value>jdbc:mysql://localhost:3306/test2</value>
</property>
</bean>
<!-- end 配置各个数据源的特性 -->
5. 编写spring配置文件配置多数据源映射关系
<bean class="com.frogking.datasource.DynamicDataSource" id="dataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry value-ref=" adminDataSource " key="Admin"></entry>
<entry value-ref=" userDataSource " key="User"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="adminDataSource"></property>
</bean>
在这个配置中第一个property属性配置目标数据源,<map key-type="java.lang.String">中的key-type必须要和静态键值对照类DataSourceConst中的值的类型相 同;<entry key="User" value-ref="userDataSource"/>中key的值必须要和静态键值对照类中的值相同,如果有多个值,可以配置多个< entry>标签。第二个property属性配置默认的数据源。
6. 配置hibernate,和普通的hibernate、spring结合的配置一样:
<!-- sessionFactory的配置 -->
<BEAN class="org".springframework.orm.hibernate3.LocalSessionFactoryBean id=sessionFactory>
<property name="dataSource">
<REF local="dataSource"> </REF>
</property>
<!-- 实体类资源映射 -->
<property name="mappingResources">
<LIST>
<VALUE>com/frogking/entity/User.hbm.xml </VALUE>
<VALUE>com/frogking/entity/Admin.hbm.xml</VALUE> </LIST>
</property>
<!-- 为sessionFactory 配置Hibernate属性 -->
<property name="hibernateProperties">
<PROPS>
<PROP key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</PROP>
<PROP key="hibernate.show_sql">true</PROP>
<PROP key="hibernate.connection.autocommit">false</PROP>
<PROP key="hibernate.cache.use_query_cache">false</PROP>
<PROP key="hibernate.max_fetch_depth">2</PROP>
<PROP key="hibernate.bytecode.use_reflection_optimizer">true</PROP>
</PROPS>
</property>
</BEAN>
<!-- 为dao配置sessionFactory -->
<BEAN class="com.frogking.dao.LoginHibernateDao" id=loginDao>
<property name="sessionFactory">
<REF local="sessionFactory"> </REF>
</property>
</BEAN>
基于spring和ibatis的多数据源切换方案编辑
基本介绍:
在仅使用ibatis时,多数据源简直就是梦魇,每多一个数据源就需要多一份sql-map-config配置文件。
采用spring的AbstractRoutingDataSource就可以简单的解决这个问题。
AbstractRoutingDataSource实现了javax.sql.DataSource接口,因此可以理解为一个虚拟的动态DataSource,在需要的时候根据上下文Context动态决定使用哪个数据源。
该方案的优势:
首先,这个方案完全是在spring的框架下解决的,数据源依然配置在spring的配置文件中,sessionFactory依然去配置它的dataSource属性,它甚至都不知道dataSource的改变。唯一不同的是在真正的dataSource与sessionFactory之间增加了一个MultiDataSource。
其次,实现简单,易于维护。这个方案虽然我说了这么多东西,其实都是分析,真正需要我们写的代码就只有MultiDataSource、SpObserver两个类。MultiDataSource类真正要写的只有getDataSource()和getDataSource(sp)两个方法,而SpObserver类更简单了。实现越简单,出错的可能就越小,维护性就越高。
最后,这个方案可以使单数据源与多数据源兼容。这个方案完全不影响BUS和DAO的编写。如果我们的项目在开始之初是单数据源的情况下开发,随着项目的进行,需要变更为多数据源,则只需要修改spring配置,并少量修改MVC层以便在请求中写入需要的数据源名,变更就完成了。如果我们的项目希望改回单数据源,则只需要简单修改配置文件。这样,为我们的项目将增加更多的弹性。
该方案的缺点
没有能够解决多用户访问单例“sessionFactory”时共享“dataSource”变量,导致产生争抢“dataSource”的结果,本质类似于操作系统中的“生产者消费者”问题。因此当多用户访问时,多数据源可能会导致系统性能下降的后果。