简介:
Spring动态配置多数据源,即在大型应用中对数据进行切分,并且采用多个数据库实例进行管理,这样可以有效提高系统的水平伸缩性。而这样的方案就会不 同于常见的单一数据实例的方案,这就要程序在运行时根据当时的请求及系统状态来动态的决定将数据存储在哪个数据库实例中,以及从哪个数据库提取数据。
Spring对于多数据源,以数据库表为参照,大体上可以分成两大类情况:
一是,表级上的跨数据库。即,对于不同的数据库却有相同的表(表名和表结构完全相同)。
二是,非表级上的跨数据库。即,多个数据源不存在相同的表。
多数据源实现
Spring2.x的版本中采用Proxy模式,就是我们在方案中实现一个虚拟的数据源,并且 用它来封装数据源选择逻辑,这样就可以有效地将数据源选择逻辑从Client中分离出来。Client提供选择所需的上下文(因为这是Client所知道 的),由虚拟的DataSource根据Client提供的上下文来实现数据源的选择。
具体的实现就是,虚拟的DataSource仅需继承AbstractRoutingDataSource实现determineCurrentLookupKey()在其中封装数据源的选择逻辑。
配置方法:
1、数据源的名称常量类:
/** * 数据源的名称常量类 * @author Administrator * */ public class DataSourceConst { public static final String USERDB = "USERDB"; public static final String SCOREDB = "SCOREDB"; }
2、改变数据源名称类:
/** * 改变数据源的名称类 * @author Administrator * */ public class DataSourceHandle { /** * 线程本地环境 */ @SuppressWarnings("unchecked") private static final ThreadLocal contextHolder = new ThreadLocal(); /** * 设置数据源类型 * @param dataSourceType */ @SuppressWarnings("unchecked") public static void setDataSourceType(String dataSourceType) { contextHolder.set(dataSourceType); } /** * 获取数据源类型 * @return */ public static String getDataSourceType() { return (String) contextHolder.get(); } /** * 清除数据源类型 */ public static void clearDataSourceType() { contextHolder.remove(); } }
3、动态数据源类:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * 动态数据源类 * 这个类必须继承AbstractRoutingDataSource, * 且实现方法 determineCurrentLookupKey,该方法返回一个Object,一般是返回字符串 * @author Administrator * */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { // 在进行DAO操作前,通过上下文环境变量,获得数据源的类型 return DataSourceHandle.getDataSourceType(); } }
4、 spring配置文件中配置多个数据源
<!-- 数据源基本配置 --> <bean id="basicDataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"> <property name="driverClass" value="com.mysql.jdbc.Driver" /> <property name="minPoolSize" value="2" /> <property name="maxPoolSize" value="20" /> <property name="maxIdleTime" value="1800" /> <property name="acquireIncrement" value="2" /> <property name="maxStatements" value="0" /> <property name="initialPoolSize" value="3" /> <property name="idleConnectionTestPeriod" value="1800" /> <property name="acquireRetryAttempts" value="30" /> <property name="breakAfterAcquireFailure" value="true" /> <property name="testConnectionOnCheckout" value="false" /> </bean> <!-- csoa dataSource --> <bean id="dataSourceUser" parent="basicDataSource"> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/userdb" /> <property name="user" value="root" /> <property name="password" value="admin" /> </bean> <!-- wa dataSource --> <bean id="dataSourceScore" parent="basicDataSource"> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/scoredb" /> <property name="user" value="root" /> <property name="password" value="admin" /> </bean> <!-- data source 抽象类 --> <bean id="dataSource" class="com.webterren.csoa.util.dbutil.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry value-ref="dataSourceUser" key="USERDB"></entry> <entry value-ref="dataSourceScore" key="SCOREDB"></entry> </map> </property> <property name="defaultTargetDataSource" ref="dataSourceUser"></property><!-- 默认数据源 --> </bean> <!-- MyBatis SQLSessionFactory --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource"></property> <property name="configLocation" value="classpath:config/mybatis/Configuration.xml" /> </bean>
这里依个人情况而定
测试:
1、SQL语句:
<select id="countUser" resultType="int"> select count(*) from user </select> <select id="countScore" resultType="int"> select count(*) from score </select>
2、测试方法
SqlSession session = null; //user DataSourceHandle.setDataSourceType(DataSourceConst.USERDB); session = this.getSqlSession(); int countUser = (Integer)session.selectOne("DbTest.countUser",""); session.close(); //score DataSourceHandle.setDataSourceType(DataSourceConst.SCOREDB); session = this.getSqlSession(); int countScore = (Integer)session.selectOne("DbTest.countScore",""); session.close();