我们很多项目中业务都需要涉及到多个数据源,最简单的做法就是直接在java代码里面lookup需要的数据源,但是这样的做法很明显耦合度太高了,
而且当逻辑流程不够严谨的时候就会出现各种大家不愿意看到的问题,由于我们现在的大多项目已经离不开spring了,spring也提供各种强大的功能,
很明显这种动态数据源功能也包括在内,具体实现类请看org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
这里我演示下如何使用spring提供的动态数据源
先写个接口,default设置为null是因为当程序里没有找到相关联的源就会调用默认源
- /**
- * 数据源切换接口
- *
- * @author shadow
- * @create 2013.04.03
- */
- public interface DataSourceEntry {
- // 默认数据源
- public final static String DEFAULT_SOURCE = null;
- /**
- * 还原数据源
- *
- * @param joinPoint
- */
- public void restore(JoinPoint join);
- /**
- * 设置数据源
- *
- * @param dataSource
- */
- public void set(String source);
- /**
- * 获取数据源
- *
- * @return String
- */
- public String get();
- /**
- * 清空数据源
- */
- public void clear();
- }
然后写个实现类,从当前线程里取出对应的数据源名
- /**
- * 数据源切换实现类类
- *
- * @author shadow
- * @create 2013.04.03
- */
- public class DataSourceEntryImpl implements DynamicTypeEntry {
- private final static ThreadLocal<String> local = new ThreadLocal<String>();
- public void clear() {
- local.remove();
- }
- public String get() {
- return local.get();
- }
- public void restore(JoinPoint join) {
- local.set(DEFAULT_SOURCE);
- }
- public void set(String source) {
- local.set(source);
- }
- }
然后写个继承AbstractRoutingDataSource的类,并注入DataSourceEntry,重写determineCurrentLookupKey模版方法
- /**
- * 获取数据源(依赖SPRING框架)
- *
- * @author shadow
- * @create 2013.04.03
- */
- public class DynamicDataSource extends AbstractRoutingDataSource {
- private DataSourceEntry dataSourceEntry;
- @Override
- protected Object determineCurrentLookupKey() {
- return this.dataSourceEntry.get();
- }
- @Resource
- public void setDataSourceEntry(DataSourceEntry dataSourceEntry) {
- this.dataSourceEntry = dataSourceEntry;
- }
- }
最后就是配置下xml文件,以后只需要直接管理dynamicDataSource这个接口就可以了,至于他内部是哪个数据源是不需要关注,写的切面还原是为了保证每次调用完另外的数据源
都会还原成默认数据源,防止有的人忘记设置回默认的,导致其他代码出问题
- <!-- JDBC模板 -->
- <bean id="jdbcTemplate"
- class="org.springframework.jdbc.core.JdbcTemplate">
- <property name="dataSource" ref="dynamicDataSource" />
- </bean>
- <!-- 获取数据源配置 -->
- <bean
- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
- <property name="locations">
- <value>classpath:properties/jdbc.properties</value>
- </property>
- </bean>
- <!-- 配置动态数据源 -->
- <bean id="dynamicDataSource"
- class="com.shadow.system.base.source.DynamicDataSource">
- <!-- 通过key-value的形式来关联数据源 -->
- <property name="targetDataSources">
- <map key-type="java.lang.String">
- <entry value-ref="C3P0_MYSQL" key="C3P0_MYSQL"></entry>
- <entry value-ref="C3P0_MYSQL2" key="C3P0_MYSQL2"></entry>
- </map>
- </property>
- <property name="defaultTargetDataSource" ref="C3P0_MYSQL" />
- </bean>
- <!-- JNDI方式 -->
- <bean id="C3P0_MYSQL"
- class="org.springframework.jndi.JndiObjectFactoryBean">
- <property name="resourceRef">
- <value>false</value>
- </property>
- <property name="jndiName">
- <value>${JNDI.template}</value>
- </property>
- </bean>
- <!-- JNDI方式 -->
- <bean id="C3P0_MYSQL2"
- class="org.springframework.jndi.JndiObjectFactoryBean">
- <property name="resourceRef">
- <value>false</value>
- </property>
- <property name="jndiName">
- <value>${JNDI.test}</value>
- </property>
- </bean>
- <!-- 配置数据源切换实现类 -->
- <bean id="dataSourceEntry"
- class="com.shadow.system.base.source.DataSourceEntryImpl" />
- <!-- 切面还原默认数据源 -->
- <aop:config>
- <aop:aspect id="dataSourceHolderAdviceAspect"
- ref="dataSourceEntry">
- <aop:after method="restore"
- pointcut="execution(* com.shadow.mvc.service.*Service.*(..))" />
- </aop:aspect>
- </aop:config>
至于程序里如何变换数据源,你可以在切面上检测哪些方法加入before方法,或者在程序里直接使用DataSourceEntry调用set方法,具体的怎么用不作代码说明了