原来写过一篇基于SSM框架配置多数据源,但是在控制器中使用时需要使用代码切换数据源并进行关闭,相对来说比较麻烦,近期在项目开发中,使用了一种新的多数据源配置方法,在service中通过注解的方式设置数据源。下面介绍具体的实现步骤。
(一)数据源切换及选择处理工具类引入
(1)创建注解类(后面设置数据源时需要使用本注解)
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface DataSource { String value(); }
(2)创建数据源切面类(获取当前线程数据源路由的key值)
public class DataSourceAspect { /** * 在dao层方法之前获取datasource对象之前在切面中指定当前线程数据源路由的key */ public void before(JoinPoint point) { Object target = point.getTarget(); String method = point.getSignature().getName(); Class<?>[] classz = target.getClass().getInterfaces(); Class<?>[] parameterTypes = ((MethodSignature) point.getSignature()).getMethod().getParameterTypes(); try { Method m = classz[0].getMethod(method, parameterTypes); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource data = m.getAnnotation(DataSource.class); HandleDataSource.putDataSource(data.value()); } } catch (Exception e) { e.printStackTrace(); } } }
同时在springmv-mybatis配置文件中配置切面:
<!-- 为业务逻辑层的方法解析@DataSource注解 为当前线程的routeholder注入数据源key --> <bean id="dataSourceAspect" class="com.common.datasource.DataSourceAspect" /> <aop:config proxy-target-class="true"> <aop:aspect id="dataSourceAspect" ref="dataSourceAspect" order="1"> <aop:pointcut id="tx" expression="execution(* com..service..*.*(..)) "/> <aop:before pointcut-ref="tx" method="before" /> </aop:aspect> </aop:config>
(3)创建数据源处理类
public class HandleDataSource { public static final ThreadLocal<String> holder = new ThreadLocal<String>(); /** * 绑定当前线程数据源路由 * * @param datasource */ public static void putDataSource(String datasource) { holder.set(datasource); } /** * 获取当前线程的数据源路由 * * @return */ public static String getDataSource() { return holder.get(); } }
(4)创建数据源选择类
public class ChooseDataSource extends AbstractRoutingDataSource{ /** * 获取与数据源相关的key * 此key是Map<String,DataSource> resolvedDataSources 中与数据源绑定的key值 * 在通过determineTargetDataSource获取目标数据源时使用 */ @Override protected Object determineCurrentLookupKey() { // TODO Auto-generated method stub return HandleDataSource.getDataSource(); } }
通过以上四个类的创建,实现了整个数据源配置和切换过程的底层处理配置,接下来就是框架中的一些基本配置。
(二)项目开发所需数据源配置,开发使用的是SSM框架,所以在jdbc.properties配置文件中配置相关数据库连接信息(以配置三个不同数据源为例)
#源数据库(数据源一) jdbc.driver=com.mysql.jdbc.Driver jdbc.url=jdbc:mysql://localhost:3306/simple-cmate?useUnicode=true&characterEncoding=UTF-8 jdbc.username=root jdbc.password=123456 #基础数据库(数据源二) base.driver=com.mysql.jdbc.Driver base.url=jdbc:mysql://localhost:3306/sys-cmate?useUnicode=true&characterEncoding=UTF-8 base.username=root base.password=123456 #业务数据库(数据源三) gateway.driver=com.mysql.jdbc.Driver gateway.url=jdbc:mysql://localhost:3306/c-gateway?useUnicode=true&characterEncoding=UTF-8 gateway.username=root gateway.password=123456 #初始化连接大小 jdbc.initialSize=10 #连接池最大数量 jdbc.maxActive=20 #连接池最小空闲 jdbc.minIdle=1 #获取连接最大等待时间 jdbc.maxWait=60000 #验证语句 jdbc.validationQuery=SELECT 1
数据源配置待用。
(三)修改spring-mybatis配置文件,对多个数据源进行配置(关键配置)
配置过程中,主要进行两方面的配置,首先对设置的几个数据源信息进行基础的配置,另外进行数据源路由配置。详情如下(以三个数据源为例,其他类似):
(1)数据源基本配置,在这个过程中为每个数据源配置bean设置一个唯一的id值,实际运用过程中需要通过这个key值切换到具体的数据源
<!-- 第一个数据源 --> <bean id="simpleDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="clone"> // <!-- 基本属性driverClassName、 url、user、password --> <property name="driverClassName" value="${jdbc.driver}" /> //value值为上述第二步中数据源一的驱动名 <property name="url" value="${jdbc.url}" /> //value值为上述第二步中数据源一的数据库连接名 <property name="username" value="${jdbc.username}" /> //value值为上述第二步中数据源一的数据库连接用户名 <property name="password" value="${jdbc.password}" /> //value值为上述第二步中数据源一的数据库连接密码 <!-- 配置初始化大小、最小、最大 --> <!-- 通常来说,只需要修改initialSize、minIdle、maxActive --> <!-- 初始化时建立物理连接的个数,缺省值为0 --> <property name="initialSize" value="${jdbc.initialSize}" /> <!-- 最小连接池数量 --> <property name="minIdle" value="${jdbc.minIdle}" /> <!-- 最大连接池数量,缺省值为8 --> <property name="maxActive" value="${jdbc.maxActive}" /> <!-- 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 --> <property name="maxWait" value="${jdbc.maxWait}" /> <!--验证语句--> <property name="validationQuery" value="${jdbc.validationQuery}"/> </bean> <!-- 第二个数据源 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="clone"> <!-- 基本属性driverClassName、 url、user、password --> <property name="driverClassName" value="${base.driver}" /> //value值为上述第二步中数据源二的连接驱动 <property name="url" value="${base.url}" /> //value值为上述第二步中数据源二的数据库连接名 <property name="username" value="${base.username}" /> //value值为上述第二步中数据源二的数据库连接用户名 <property name="password" value="${base.password}" /> //value值为上述第二步中数据源二的数据库连接密码 <!-- 配置初始化大小、最小、最大 --> <!-- 通常来说,只需要修改initialSize、minIdle、maxActive --> <!-- 初始化时建立物理连接的个数,缺省值为0 --> <property name="initialSize" value="${jdbc.initialSize}" /> <!-- 最小连接池数量 --> <property name="minIdle" value="${jdbc.minIdle}" /> <!-- 最大连接池数量,缺省值为8 --> <property name="maxActive" value="${jdbc.maxActive}" /> <!-- 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 --> <property name="maxWait" value="${jdbc.maxWait}" /> <!--验证语句--> <property name="validationQuery" value="${jdbc.validationQuery}"/> </bean> <!-- 业务数据源(数据源三) --> <bean id="gatewayDataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="clone"> <!-- 基本属性driverClassName、 url、user、password --> <property name="driverClassName" value="${gateway.driver}" /> //value值为上述第二步中数据源三的连接驱动 <property name="url" value="${gateway.url}" /> //value值为上述第二步中数据源三的数据库连接名 <property name="username" value="${gateway.username}" /> //value值为上述第二步中数据源三的数据库连接用户名 <property name="password" value="${gateway.password}" /> //value值为上述第二步中数据源三的数据库连接密码 <!-- 配置初始化大小、最小、最大 --> <!-- 通常来说,只需要修改initialSize、minIdle、maxActive --> <!-- 初始化时建立物理连接的个数,缺省值为0 --> <property name="initialSize" value="${jdbc.initialSize}" /> <!-- 最小连接池数量 --> <property name="minIdle" value="${jdbc.minIdle}" /> <!-- 最大连接池数量,缺省值为8 --> <property name="maxActive" value="${jdbc.maxActive}" /> <!-- 获取连接时最大等待时间,单位毫秒。配置了maxWait之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置useUnfairLock属性为true使用非公平锁。 --> <property name="maxWait" value="${jdbc.maxWait}" /> <!--验证语句--> <property name="validationQuery" value="${jdbc.validationQuery}"/> </bean>
数据源基础信息配置完成后,进行核心的数据源切换路由配置,只是多数据源配置的核心,上述定义的数据源都需要在数据源路由中进行正确的定义和配置后才能正常的切换和运行。
(2)数据源路由配置,配置一个默认数据源,其他数据源为非默认数据源
<!-- 数据源路由 --> <bean id="multipleDataSource" class="com.common.datasource.ChooseDataSource"> <!-- 默认数据源 --> <property name="defaultTargetDataSource" ref="simpleDataSource"/> <!-- 目标数据源 --> <property name="targetDataSources"> <map> <!-- 注意这里的value是和上面的DataSource的id对应,key要和 下面的DataSourceContextHolder中的常量对应 --> <entry value-ref="simpleDataSource" key="simpleDataSource"/> <entry value-ref="dataSource" key="dataSource"/> <entry value-ref="gatewayDataSource" key="gatewayDataSource"/> </map> </property> </bean>
同时配置事务管理,关联数据源
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <!-- 关联数据源 --> <property name="dataSource" ref="multipleDataSource"></property> </bean> <!-- 注解事务 --> <tx:annotation-driven transaction-manager="transactionManager" />
数据源路由配置完成后整个多数据源的配置就大功告成了,接下来就是具体的使用。
备注:在spring-mybatis中进行数据源基础信息和数据源路由配置时,当增加新的数据源时,都需要为该数据源配置一个新的bean,同时在数据源路由中注入该bean。
(四)使用多数据源
多数据源的切换和配置再service层的接口类中实现,通过数据源注解为每一个方法执行的数据源进行具体的配置,如下:
/** * 保存对象 * @param sysMenu */ @DataSource("dataSource") //注解中的值为配置文件中相应数据源对应的bean的id值 void save(SysMenu sysMenu);
通过以上四步,我们就完成了多数据源的配置与使用,在这个过程中,首先,我们一定要将多个数据源的配置与相应数据源一一对应起来,另外,在使用的时候,数据源注解中的值一定要和相应数据源配置文件中的bean的id值对应。