Spring多数据源配置二
2017-03-18 21:42
211 查看
继承Spring的AbstractRoutingDataSource来实现多数据源配置
1. 数据源配置
5. 数据源动态切换
1) 方式一: 定义切面,设置切面在数据库事物开启前作用,切换数据源
注意,需要将数据源动态切换的切面的执行顺序设置为1,将数据库事物管理的执行顺序设置为2,在数据库
事物开启前进行数据源切换
至此,方式一 多个数据源配置以及数据源动态切换功能已经实现,完整配置如下
2)方式二:定义注解,通过注解的值来获取当前数据源,并进行切换
定义注解,作用于类和方法
aop:before 在数据库事物开启前进行数据源切换
至此,方式二 多个数据源配置以及数据源动态切换功能已经实现,完整配置如下
@DataSource注解使用示例:
方式一与方式二对比:
方式一,需要为每个数据源service层单独建一个包,一个Service只能使用一个数据源
方式二,不需要为每个数据源service层单独建一个包,一个Service可以使用多个数据源
参考文章:
http://blog.csdn.net/wangpeng047/article/details/8866239/
http://blog.csdn.net/gaofuqi/article/details/46417281
http://www.cnblogs.com/liujiduo/p/5004691.html
http://blog.csdn.net/qqxhwwqwq/article/details/51678595
1. 数据源配置
<!-- 数据库连接池配置 --> <bean id="dataSourceTask" name="dataSourceTask" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 指定连接数据库的驱动--> <property name="driverClass" value="${db.task.jdbc.driverClassName}"/> <!-- 指定连接数据库的URL--> <property name="jdbcUrl" value="${db.task.jdbc.url}"/> <!-- 指定连接数据库的用户名--> <property name="user" value="${db.task.jdbc.user}"/> <!-- 指定连接数据库的密码--> <property name="password" value="${db.task.jdbc.password}"/> <!-- 指定连接池中保留的最大连接数. Default:15--> <property name="maxPoolSize" value="${db.task.jdbc.maxPoolSize}"/> <!-- 指定连接池中保留的最小连接数--> <property name="minPoolSize" value="${db.task.jdbc.minPoolSize}"/> <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3--> <property name="initialPoolSize" value="${db.task.jdbc.initialPoolSize}"/> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0--> <property name="maxIdleTime" value="${db.task.jdbc.maxIdleTime}"/> <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3--> <property name="acquireIncrement" value="${db.task.jdbc.acquireIncrement}"/> <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection 而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0--> <property name="maxStatements" value="${db.task.jdbc.maxStatements}"/> <!-- 每60秒检查所有连接池中的空闲连接.Default:0 --> <property name="idleConnectionTestPeriod" value="${db.task.jdbc.idleConnectionTestPeriod}"/> <!--连接池获取新连接的时间,超时后将 抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout" value="${db.task.jdbc.checkoutTimeout}"/> </bean> <bean id="dataSourceEnv" name="dataSourceEnv" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 指定连接数据库的驱动--> <property name="driverClass" value="${db.lcmyw.jdbc.driverClassName}"/> <!-- 指定连接数据库的URL--> <property name="jdbcUrl" value="${db.lcmyw.jdbc.url}"/> <!-- 指定连接数据库的用户名--> <property name="user" value="${db.lcmyw.jdbc.user}"/> <!-- 指定连接数据库的密码--> <property name="password" value="${db.lcmyw.jdbc.password}"/> <!-- 指定连接池中保留的最大连接数. Default:15--> <property name="maxPoolSize" value="${db.lcmyw.jdbc.maxPoolSize}"/> <!-- 指定连接池中保留的最小连接数--> <property name="minPoolSize" value="${db.lcmyw.jdbc.minPoolSize}"/> <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3--> <property name="initialPoolSize" value="${db.lcmyw.jdbc.initialPoolSize}"/> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0--> <property name="maxIdleTime" value="${db.lcmyw.jdbc.maxIdleTime}"/> <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3--> <property name="acquireIncrement" value="${db.lcmyw.jdbc.acquireIncrement}"/> <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection 而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0--> <property name="maxStatements" value="${db.lcmyw.jdbc.maxStatements}"/> <!-- 每60秒检查所有连接池中的空闲连接.Default:0 --> <property name="idleConnectionTestPeriod" value="${db.lcmyw.jdbc.idleConnectionTestPeriod}"/> <!--连接池获取新连接的时间,超时后将 抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout" value="${db.lcmyw.jdbc.checkoutTimeout}"/> </bean>2. 定义一个类继承AbstractRoutingDataSource实现determineCurrentLookupKey方法,来实现数据库的动态切换
package com.johnfnash.learn.pro.dashboardserver.core; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; /** * * ClassName: DynamicDataSource <br/> * Function: 扩展Spring的AbstractRoutingDataSource抽象类,实现动态数据源. <br/> * date: 2017年3月15日 下午10:23:52 <br/> * * @author JohnFNash * @version * @since JDK 1.6 */ public class DynamicDataSource extends AbstractRoutingDataSource { @Override protected Object determineCurrentLookupKey() { // 从自定义的位置获取数据源标识 return DynamicDataSourceHolder.getDatasource(); } }3. 定义工具类,用于动态切换数据源
package com.johnfnash.learn.pro.dashboardserver.core; /** * * ClassName: DatabaseContextHolder <br/> * Function: 当前线程中使用的数据源标识 <br/> * date: 2017年3月15日 下午10:10:17 <br/> * * @author JohnFNash * @version * @since JDK 1.6 */ public class DynamicDataSourceHolder { /** 数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰 */ private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>(); /** * 设置数据源名称 * @param dastsource 数据源名称 */ public static void setDatasource(String datasource) { contextHolder.set(datasource); } /** * 获取数据源名称 * @return 数据源名称 */ public static String getDatasource() { return contextHolder.get(); } /** * 清除标志 */ public static void clearDatasource() { contextHolder.remove(); } }4. 在数据库配置文件中添加如下配置
<!-- 动态数据源配置 --> <bean id="dataSource" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSource"> <property name="targetDataSources"> <map key-type="java.lang.String"> <entry key="dataSourceTask" value-ref="dataSourceTask"></entry> <entry key="dataSourceEnv" value-ref="dataSourceEnv"></entry> </map> </property> <property name="defaultTargetDataSource" ref="dataSourceEnv"></property> </bean> <!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 --> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSource" /> <!-- 自动扫描mapping.xml文件 --> <property name="mapperLocations" value="classpath:/mapper_*/*.xml"/> </bean> <!-- DAO接口所在包名,Spring会自动查找其下的类 --> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.johnfnash.learn.pro.dashboardserver.dao" /> <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/> </bean> <!-- 配置事物管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource" /> </bean> <!-- 拦截器方式配置事物 --> <tx:advice id="transactionAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="insert*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="select*" propagation="SUPPORTS" read-only="true" /> </tx:attributes> </tx:advice> <!-- spring aop事物管理 --> <aop:config> <aop:pointcut id="transactionPointcut" expression="execution(* com.johnfnash.learn.pro.dashboardserver.service..*Impl.*(..))" /> <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" order="2"/> </aop:config>到目前为止,动态数据源的配置以及OK,不过还不能实现动态切换,下面将介绍
5. 数据源动态切换
1) 方式一: 定义切面,设置切面在数据库事物开启前作用,切换数据源
package com.johnfnash.learn.pro.dashboardserver.core; /** * * ClassName: DynamicDataSourceInterceptor <br/> * Function: 数据源动态切换拦截器. <br/> * date: 2017年3月15日 下午10:28:17 <br/> * * @author JohnFNash * @version * @since JDK 1.6 */ public class DynamicDataSourceInterceptor { /** 切换到数据源1 */ public void setDS1() { DynamicDataSourceHolder.setDataSource("dataSourceTask"); } /** 切换到数据源2 */ public void setDS2() { DynamicDataSourceHolder.setDataSource("dataSourceEnv"); } }配置切面,进行数据源动态切换
<!-- 数据源动态切换实体 --> <bean id="dataSourceInterceptor" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSourceInterceptor"/> <!-- 数据源动态切换切面配置 --> <aop:config> <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor" order="1"> <!-- 拦截所有service实现类的方法 --> <aop:pointcut id="dataSourcePointcutTask" expression="execution(* com.johnfnash.learn.pro.dashboardserver.service.task.*Impl.*(..))"/> <aop:before pointcut-ref="dataSourcePointcutTask" method="setDS1" /> <aop:pointcut id="dataSourcePointcutEnv" expression="execution(* com.johnfnash.learn.pro.dashboardserver.service.env.*Impl.*(..))"/> <aop:before pointcut-ref="dataSourcePointcutEnv" method="setDS2" /> </aop:aspect> </aop:config>
注意,需要将数据源动态切换的切面的执行顺序设置为1,将数据库事物管理的执行顺序设置为2,在数据库
事物开启前进行数据源切换
至此,方式一 多个数据源配置以及数据源动态切换功能已经实现,完整配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 数据库连接池配置 --> <bean id="dataSourceTask" name="dataSourceTask" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 指定连接数据库的驱动--> <property name="driverClass" value="${db.task.jdbc.driverClassName}"/> <!-- 指定连接数据库的URL--> <property name="jdbcUrl" value="${db.task.jdbc.url}"/> <!-- 指定连接数据库的用户名--> <property name="user" value="${db.task.jdbc.user}"/> <!-- 指定连接数据库的密码--> <property name="password" value="${db.task.jdbc.password}"/> <!-- 指定连接池中保留的最大连接数. Default:15--> <property name="maxPoolSize" value="${db.task.jdbc.maxPoolSize}"/> <!-- 指定连接池中保留的最小连接数--> <property name="minPoolSize" value="${db.task.jdbc.minPoolSize}"/> <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3--> <property name="initialPoolSize" value="${db.task.jdbc.initialPoolSize}"/> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0--> <property name="maxIdleTime" value="${db.task.jdbc.maxIdleTime}"/> <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3--> <property name="acquireIncrement" value="${db.task.jdbc.acquireIncrement}"/> <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection 而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0--> <property name="maxStatements" value="${db.task.jdbc.maxStatements}"/> <!-- 每60秒检查所有连接池中的空闲连接.Default:0 --> <property name="idleConnectionTestPeriod" value="${db.task.jdbc.idleConnectionTestPeriod}"/> <!--连接池获取新连接的时间,超时后将 抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout" value="${db.task.jdbc.checkoutTimeout}"/> </bean> <bean id="dataSourceEnv" name="dataSourceEnv" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 指定连接数据库的驱动--> <property name="driverClass" value="${db.lcmyw.jdbc.driverClassName}"/> <!-- 指定连接数据库的URL--> <property name="jdbcUrl" value="${db.lcmyw.jdbc.url}"/> <!-- 指定连接数据库的用户名--> <property name="user" value="${db.lcmyw.jdbc.user}"/> <!-- 指定连接数据库的密码--> <property name="password" value="${db.lcmyw.jdbc.password}"/> <!-- 指定连接池中保留的最大连接数. Default:15--> <property name="maxPoolSize" value="${db.lcmyw.jdbc.maxPoolSize}"/> <!-- 指定连接池中保留的最小连接数--> <property name="minPoolSize" value="${db.lcmyw.jdbc.minPoolSize}"/> <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3--> <property name="initialPoolSize" value="${db.lcmyw.jdbc.initialPoolSize}"/> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0--> <property name="maxIdleTime" value="${db.lcmyw.jdbc.maxIdleTime}"/> <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3--> <property name="acquireIncrement" value="${db.lcmyw.jdbc.acquireIncrement}"/> <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection 而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0--> <property name="maxStatements" value="${db.lcmyw.jdbc.maxStatements}"/> <!-- 每60秒检查所有连接池中的空闲连接.Default:0 --> <property name="idleConnectionTestPeriod" value="${db.lcmyw.jdbc.idleConnectionTestPeriod}"/> <!--连接池获取新连接的时间,超时后将 抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout" value="${db.lcmyw.jdbc.checkoutTimeout}"/> </bean>
<bean id="dataSource" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSourceTask" value-ref="dataSourceTask"></entry>
<entry key="dataSourceEnv" value-ref="dataSourceEnv"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceEnv"></property>
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:/mapper_*/*.xml"/>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.johnfnash.learn.pro.dashboardserver.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 配置事物管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- spring aop事物管理 -->
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(* com.johnfnash.learn.pro.dashboardserver.service..*Impl.*(..))" />
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" order="2"/>
<!-- <aop:advisor pointcut-ref="transactionPointcut" advice-ref="dataSourceInterceptor" order="1"/> -->
</aop:config>
<!-- 数据源动态切换切面配置 -->
<aop:config>
<aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor" order="1">
<aop:pointcut id="dataSourcePointcutTask"
expression="execution(* com.johnfnash.learn.pro.dashboardserver.service.task.*Impl.*(..))"/>
<aop:before pointcut-ref="dataSourcePointcutTask" method="setDS1" />
<aop:pointcut id="dataSourcePointcutEnv"
expression="execution(* com.johnfnash.learn.pro.dashboardserver.service.env.*Impl.*(..))"/>
<aop:before pointcut-ref="dataSourcePointcutEnv" method="setDS2" />
</aop:aspect>
</aop:config>
<!-- 数据源动态切换实体 -->
<bean id="dataSourceInterceptor" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSourceInterceptor"/>
</beans>
2)方式二:定义注解,通过注解的值来获取当前数据源,并进行切换
定义注解,作用于类和方法
package com.johnfnash.learn.pro.dashboardserver.core; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target({ ElementType.TYPE, ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value(); }定义拦截器,解析注解切换数据源
package com.johnfnash.learn.pro.dashboardserver.core; import java.lang.reflect.Method; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.reflect.MethodSignature; /** * * ClassName: DynamicDataSourceInterceptor <br/> * Function: 数据源动态切换拦截器. <br/> * date: 2017年3月15日 下午10:28:17 <br/> * * @author JohnFNash * @version * @since JDK 1.6 */ public class DynamicDataSourceInterceptor { /** * 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源 * * @param point * @throws Exception */ public void intercept(JoinPoint point) throws Exception { Class<?> target = point.getTarget().getClass(); MethodSignature signature = (MethodSignature) point.getSignature(); resolveDataSource(target, signature.getMethod()); } /** * 提取目标对象方法注解和类型注解中的数据源标识 * * @param clazz * @param method */ private void resolveDataSource(Class<?> clazz, Method method) { try { Class<?>[] types = method.getParameterTypes(); // 默认使用类型注解 if (clazz.isAnnotationPresent(DataSource.class)) { DataSource source = clazz.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } // 方法注解可以覆盖类型注解 Method m = clazz.getMethod(method.getName(), types); if (m != null && m.isAnnotationPresent(DataSource.class)) { DataSource source = m.getAnnotation(DataSource.class); DynamicDataSourceHolder.setDataSource(source.value()); } } catch (Exception e) { e.printStackTrace(); } } }在配置文件中配置切面,实现数据源动态切换
<!-- 数据源动态切换切面配置 --> <aop:config> <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor" order="1"> <!-- 拦截所有service实现类的方法 --> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.johnfnash.learn.pro.dashboardserver.service..*Impl.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config> <!-- 数据源动态切换实体 --> <bean id="dataSourceInterceptor" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSourceInterceptor"/>注意:设置执行顺序为1,并使用
aop:before 在数据库事物开启前进行数据源切换
至此,方式二 多个数据源配置以及数据源动态切换功能已经实现,完整配置如下
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 数据库连接池配置 --> <bean id="dataSourceTask" name="dataSourceTask" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 指定连接数据库的驱动--> <property name="driverClass" value="${db.task.jdbc.driverClassName}"/> <!-- 指定连接数据库的URL--> <property name="jdbcUrl" value="${db.task.jdbc.url}"/> <!-- 指定连接数据库的用户名--> <property name="user" value="${db.task.jdbc.user}"/> <!-- 指定连接数据库的密码--> <property name="password" value="${db.task.jdbc.password}"/> <!-- 指定连接池中保留的最大连接数. Default:15--> <property name="maxPoolSize" value="${db.task.jdbc.maxPoolSize}"/> <!-- 指定连接池中保留的最小连接数--> <property name="minPoolSize" value="${db.task.jdbc.minPoolSize}"/> <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3--> <property name="initialPoolSize" value="${db.task.jdbc.initialPoolSize}"/> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0--> <property name="maxIdleTime" value="${db.task.jdbc.maxIdleTime}"/> <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3--> <property name="acquireIncrement" value="${db.task.jdbc.acquireIncrement}"/> <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection 而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0--> <property name="maxStatements" value="${db.task.jdbc.maxStatements}"/> <!-- 每60秒检查所有连接池中的空闲连接.Default:0 --> <property name="idleConnectionTestPeriod" value="${db.task.jdbc.idleConnectionTestPeriod}"/> <!--连接池获取新连接的时间,超时后将 抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout" value="${db.task.jdbc.checkoutTimeout}"/> </bean> <bean id="dataSourceEnv" name="dataSourceEnv" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <!-- 指定连接数据库的驱动--> <property name="driverClass" value="${db.lcmyw.jdbc.driverClassName}"/> <!-- 指定连接数据库的URL--> <property name="jdbcUrl" value="${db.lcmyw.jdbc.url}"/> <!-- 指定连接数据库的用户名--> <property name="user" value="${db.lcmyw.jdbc.user}"/> <!-- 指定连接数据库的密码--> <property name="password" value="${db.lcmyw.jdbc.password}"/> <!-- 指定连接池中保留的最大连接数. Default:15--> <property name="maxPoolSize" value="${db.lcmyw.jdbc.maxPoolSize}"/> <!-- 指定连接池中保留的最小连接数--> <property name="minPoolSize" value="${db.lcmyw.jdbc.minPoolSize}"/> <!-- 指定连接池的初始化连接数 取值应在minPoolSize 与 maxPoolSize 之间.Default:3--> <property name="initialPoolSize" value="${db.lcmyw.jdbc.initialPoolSize}"/> <!-- 最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。 Default:0--> <property name="maxIdleTime" value="${db.lcmyw.jdbc.maxIdleTime}"/> <!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数. Default:3--> <property name="acquireIncrement" value="${db.lcmyw.jdbc.acquireIncrement}"/> <!-- JDBC的标准,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements属于单个connection 而不是整个连接池所以设置这个参数需要考虑到多方面的因数.如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default:0--> <property name="maxStatements" value="${db.lcmyw.jdbc.maxStatements}"/> <!-- 每60秒检查所有连接池中的空闲连接.Default:0 --> <property name="idleConnectionTestPeriod" value="${db.lcmyw.jdbc.idleConnectionTestPeriod}"/> <!--连接池获取新连接的时间,超时后将 抛出SQLException,如设为0则无限期等待。单位毫秒。Default: 0 --> <property name="checkoutTimeout" value="${db.lcmyw.jdbc.checkoutTimeout}"/> </bean>
<bean id="dataSource" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSource">
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSourceTask" value-ref="dataSourceTask"></entry>
<entry key="dataSourceEnv" value-ref="dataSourceEnv"></entry>
</map>
</property>
<property name="defaultTargetDataSource" ref="dataSourceEnv"></property>
</bean>
<!-- spring和MyBatis完美整合,不需要mybatis的配置映射文件 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!-- 自动扫描mapping.xml文件 -->
<property name="mapperLocations" value="classpath:/mapper_*/*.xml"/>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.johnfnash.learn.pro.dashboardserver.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
</bean>
<!-- 配置事物管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 拦截器方式配置事物 -->
<tx:advice id="transactionAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="add*" propagation="REQUIRED" />
<tx:method name="insert*" propagation="REQUIRED" />
<tx:method name="update*" propagation="REQUIRED" />
<tx:method name="delete*" propagation="REQUIRED" />
<tx:method name="get*" propagation="SUPPORTS" read-only="true" />
<tx:method name="find*" propagation="SUPPORTS" read-only="true" />
<tx:method name="select*" propagation="SUPPORTS" read-only="true" />
</tx:attributes>
</tx:advice>
<!-- spring aop事物管理 -->
<aop:config>
<aop:pointcut id="transactionPointcut"
expression="execution(* com.johnfnash.learn.pro.dashboardserver.service..*Impl.*(..))" />
<!-- 设置order的值为2,使得数据库事物开启在数据源切换之后,否则数据源切换不会达到效果 -->
<aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice" order="2"/>
</aop:config>
<!-- 数据源动态切换切面配置 --> <aop:config> <aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor" order="1"> <!-- 拦截所有service实现类的方法 --> <aop:pointcut id="dataSourcePointcut" expression="execution(* com.johnfnash.learn.pro.dashboardserver.service..*Impl.*(..))"/> <aop:before pointcut-ref="dataSourcePointcut" method="intercept" /> </aop:aspect> </aop:config> <!-- 数据源动态切换实体 --> <bean id="dataSourceInterceptor" class="com.johnfnash.learn.pro.dashboardserver.core.DynamicDataSourceInterceptor"/>
</beans>
@DataSource注解使用示例:
package com.johnfnash.learn.pro.dashboardserver.service.env; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.johnfnash.learn.pro.dashboardserver.core.DataSource; import com.johnfnash.learn.pro.dashboardserver.dao.env.TaskInfoMapper; import com.johnfnash.learn.pro.dashboardserver.domain.TaskInfo; /** * * ClassName: FactTskServiceImpl <br/> * Function: 任务信息业务逻辑操作实现类 <br/> * date: 2017年3月8日 下午10:09:46 <br/> * * @author JohnFNash * @version * @since JDK 1.6 */ @Service("taskInfoService") @DataSource("dataSourceEnv") public class TaskInfoServiceImpl implements TaskInfoService { @Autowired private TaskInfoMapper taskInfoMapper; @Override public int insertTasks(List<TaskInfo> tasks) { return taskInfoMapper.insertTasks(tasks); } @Override public int updateTaskControlStatus(Map<String, Object> params) { return taskInfoMapper.updateTaskControlStatus(params); } @Override public int updateTaskControlTimestamp(Map<String, Object> params) { return taskInfoMapper.updateTaskControlTimestamp(params); } @Override public Map<String, Object> getTaskControlInfo(Map<String, Object> params) { return taskInfoMapper.getTaskControlInfo(params); } }上面 @DataSource 注解是定义在类上的,也可以定义在方法上,方法上定义的注解优先级高于定义在类上的注解
方式一与方式二对比:
方式一,需要为每个数据源service层单独建一个包,一个Service只能使用一个数据源
方式二,不需要为每个数据源service层单独建一个包,一个Service可以使用多个数据源
参考文章:
http://blog.csdn.net/wangpeng047/article/details/8866239/
http://blog.csdn.net/gaofuqi/article/details/46417281
http://www.cnblogs.com/liujiduo/p/5004691.html
http://blog.csdn.net/qqxhwwqwq/article/details/51678595
相关文章推荐
- 详解Spring Boot整合Mybatis实现 Druid多数据源配置
- 基于注解的Spring多数据源配置和使用
- spring多数据源配置方式
- Spring多数据源配置及事务管理(待续)
- spring多数据源配置
- spring多数据源配置
- spring多数据源配置
- spring 多数据源配置方式
- spring基于通用Dao的多数据源配置详解
- 多数据源配置(二):Spring-data-jpa
- spring多数据源配置
- spring中多数据源配置
- spring多数据源配置
- 基于SQL语句的Spring多数据源配置
- Spring Cloud Spring Boot mybatis分布式微服务云架构(十九)多数据源配置与使用(1)
- Spring多数据源配置
- Spring Boot + Mybatis 多数据源配置实现读写分离
- 基于注解的Spring多数据源配置和使用
- Spring+Mybatis 多数据源配置Invalid bound statement (not found)
- Spring+Mybatis 多数据源配置