MySQL数据库之通过AOP实现MyBatis多数据源的动态切换实例教程
小标 2018-11-13 来源 : 阅读 1004 评论 0

摘要:本文主要向大家介绍了MySQL数据库之通过AOP实现MyBatis多数据源的动态切换实例教程 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助。

本文主要向大家介绍了MySQL数据库之通过AOP实现MyBatis多数据源的动态切换实例教程 ,通过具体的内容向大家展现,希望对大家学习MySQL数据库有所帮助。

<


        <p>在后面的工作中,有一个项目也需要用到多<a href="https://www.2cto.com/database/" target="_blank" class="keylink">数据库</a>,但是是在一个方法中,里面涉及到两个查询,可能还要和线程进行绑定。这就涉及到在查询的时候切换数据库。这个文章写的也很不错。现在分享给大家。</p>
<p>【环境参数】</p>
<p>1.开发框架:Spring + SpringMVC + MyBatis</p>
<p>2.数据库A的URL:jdbc.url=jdbc:<a href="https://www.2cto.com/database/MySQL/" target="_blank" class="keylink">mysql</a>://172.16.17.164:3306/ test?characterEncoding=UTF-8&amp;useUnicode=TRUE&amp;autoReconnect=true&amp;failOverReadOnly=false</p>
<p>3.数据库B的URL:bakdb.jdbc.url=jdbc:mysql://172.16.17.68:3306/bakDB?characterEncoding=UTF-8&amp;useUnicode=TRUE&amp;autoReconnect=true&amp;failOverReadOnly=false</p>
<p>【需求描述】</p>
<p>(1)当用户调用X方法“之前”,<a href="https://www.2cto.com/os/" target="_blank" class="keylink">系统</a>会首先切换当前数据源为A数据源(bakDb数据库),之后再去调用方法X。</p>
<p>(2)当用户调用Y方法“之前”,系统会首先切换当前的数据源为B数据源(testDb数据库),之后再去调用方法Y。</p>
<p>(3)X方法和Y方法所在的包名</p>
<p>&nbsp; &nbsp; 3.1) X方法:该方法位于com.zjrodger.bakdata.service包下其子包下。</p>
<p>&nbsp; &nbsp; 3.2) Y方法:该方法位于com.zjrodger.datatobank.service或者com.zjrodger.zxtobank.service包及其子包下。</p>
<p>【具体步骤】</p>
<p>1、编写动态数据源相关代码。</p>
<p>(1) 编写DynamicDataSource类。</p>
<p>DynamicDataSource的主要作用是以Map的形式,来存储多个数据源。</p>
<p>因为该类继承了父类AbstractRoutingDataSource,在父类中,多数据源的实例是被存放在一个名为“targetDataSource”的Map类型的成员变量中。</p>
<p>点击(此处)折叠或打开</p>
<p>import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;</p>
<p>public class DynamicDataSource extends AbstractRoutingDataSource {</p>
<p>&nbsp; &nbsp; @Override</p>
<p>&nbsp; &nbsp; protected Object determineCurrentLookupKey() {</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; return DatabaseContextHolder.getDbType();</p>
<p>&nbsp; &nbsp; }</p>
<p>}</p>
<p>(2) 编写DatabaseContextHolder类。</p>
<p>点击(此处)折叠或打开</p>
<p>public class DatabaseContextHolder {</p>
<p>&nbsp; &nbsp; private static final ThreadLocal&lt;String&gt; contextHolder = new ThreadLocal&lt;String&gt;();</p>
<p>&nbsp; &nbsp; public static void setDbType(String dataSourceType) {</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; contextHolder.set(dataSourceType);</p>
<p>&nbsp; &nbsp; }</p>
<p>&nbsp; &nbsp; public static String getDbType() {</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; return contextHolder.get();</p>
<p>&nbsp; &nbsp; }</p>
<p>&nbsp; &nbsp; public static void clearDbType() {</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; contextHolder.remove();</p>
<p>&nbsp; &nbsp; }</p>
<p>}</p>
<p>2、编写切换数据源的拦截器。</p>
<p>点击(此处)折叠或打开</p>
<p>public class DataSourceInterceptor {</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; /** 数据源切换常量 */</p>
<p>&nbsp; &nbsp; public static final String DATASOURCE_TEST_DB="dataSourceKey4TestDb";</p>
<p>&nbsp; &nbsp; public static final String DATASOURCE_BAK_DB="dataSourceKey4BakDb";</p>
<p>&nbsp; &nbsp; /**</p>
<p>&nbsp; &nbsp; &nbsp;* 设置数据源为test数据库所对应的数据源。</p>
<p>&nbsp; &nbsp; &nbsp;* @param jp</p>
<p>&nbsp; &nbsp; &nbsp;*/</p>
<p>&nbsp; &nbsp; public void setdataSourceTestDb(JoinPoint jp) {</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; DatabaseContextHolder.setDbType(DATASOURCE_TEST_DB);</p>
<p>&nbsp; &nbsp; }</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; /**</p>
<p>&nbsp; &nbsp; &nbsp;* 设置数据源为bak数据库所对应的数据源。</p>
<p>&nbsp; &nbsp; &nbsp;* @param jp</p>
<p>&nbsp; &nbsp; &nbsp;*/</p>
<p>&nbsp; &nbsp; public void setdataSourceBakDb(JoinPoint jp) {</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; DatabaseContextHolder.setDbType(DATASOURCE_BAK_DB);</p>
<p>&nbsp; &nbsp; }</p>
<p>}</p>
<p>3、在Spring配置文件中进行相关配置。</p>
<p>(1)配置两个数据源</p>
<p>A.第一个数据源:</p>
<p>点击(此处)折叠或打开</p>
<p>&lt;bean id="c3p0DataSource4BakDb" class="com.mchange.v2.c3p0.ComboPooledDataSource"</p>
<p>&nbsp; &nbsp; destroy-method="close" depends-on="propertyConfigurer"&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="driverClass" value="${bakdb.jdbc.driverclass}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="jdbcUrl" value="${bakdb.jdbc.url}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="user" value="${bakdb.jdbc.username}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="password" value="${bakdb.jdbc.password}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="initialPoolSize" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 连接池中保留的最小连接数。 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="minPoolSize" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 连接池中保留的最大连接数。Default: 15 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="maxPoolSize" value="100" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="acquireIncrement" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 最大空闲时间,10秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="maxIdleTime" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="maxStatements" value="0" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 连接池用完时客户调用getConnection()后等待获取连接的时间,单位:毫秒。超时后会抛出 SQLEXCEPTION,如果设置0,则无限等待。Default:0 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="checkoutTimeout" value="30000" /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>B.第二个数据源:</p>
<p>点击(此处)折叠或打开</p>
<p>&lt;bean id="c3p0DataSource4TestDb" class="com.mchange.v2.c3p0.ComboPooledDataSource"</p>
<p>&nbsp; &nbsp; destroy-method="close" depends-on="propertyConfigurer"&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="driverClass" value="${jdbc.driverclass}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="jdbcUrl" value="${jdbc.url}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="user" value="${jdbc.username}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="password" value="${jdbc.password}" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="initialPoolSize" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 连接池中保留的最小连接数。 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="minPoolSize" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 连接池中保留的最大连接数。Default: 15 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="maxPoolSize" value="100" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="acquireIncrement" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 最大空闲时间,10秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="maxIdleTime" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="maxStatements" value="0" /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 连接池用完时客户调用getConnection()后等待获取连接的时间,单位:毫秒。超时后会抛出 SQLEXCEPTION,如果设置0,则无限等待。Default:0 --&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="checkoutTimeout" value="30000" /&gt;</p>
<p>&lt;/bean&gt;</p>
<p>(2)两个数据源所对应的properties属性文件</p>
<p>点击(此处)折叠或打开</p>
<p># =========== Test数据库相关信息 ============</p>
<p>jdbc.url=jdbc:mysql://172.16.17.164:3306/ test?characterEncoding=UTF-8&amp;amp;useUnicode=TRUE&amp;amp;autoReconnect=true&amp;amp;failOverReadOnly=false</p>
<p>jdbc.username=root</p>
<p>jdbc.password=123456</p>
<p>jdbc.driverclass=com.mysql.jdbc.Driver</p>
<p>jdbc.ip=172.16.5.64</p>
<p>jdbc.dbname=test</p>
<p># =========== BakDB数据库相关信息 ============</p>
<p>bakdb.jdbc.url=jdbc:mysql://172.16.17.68:3306/bakDB?characterEncoding=UTF-8&amp;amp;useUnicode=TRUE&amp;amp;autoReconnect=true&amp;amp;failOverReadOnly=false</p>
<p>bakdb.jdbc.username=root</p>
<p>bakdb.jdbc.password=123456</p>
<p>bakdb.jdbc.driverclass=com.mysql.jdbc.Driver</p>
<p>bakdb.jdbc.ip=172.16.17.68</p>
<p>bakdb.jdbc.dbname=bakDB</p>
<p>(3)配置DynamicDataSource这个Bean(关键)。</p>
<p>该DynamicDataSource的主要作用是以Map的形式,来存储多个数据源。</p>
<p>点击(此处)折叠或打开</p>
<p>&lt;!-- 配置可以存储多个数据源的Bean --&gt;</p>
<p>&lt;bean id="dataSource" class="com.beebank.pub.datasource.DynamicDataSource"&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="targetDataSources"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;map key-type="java.lang.String"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;entry key="dataSourceKey4TestDb" value-ref="c3p0DataSource4TestDb" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;entry key="dataSourceKey4BakDb" value-ref="c3p0DataSource4BakDb" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/map&gt;</p>
<p>&nbsp; &nbsp; &lt;/property&gt;</p>
<p>&nbsp; &nbsp; &lt;property name="defaultTargetDataSource" ref="c3p0DataSource4HuihangDb" /&gt;</p>
<p>&lt;/bean&gt;&nbsp;</p>
<p>配置dataSource这个Bean</p>
<p>(4)配置DataSourceInterceptor这个Bean(关键)。</p>
<p>点击(此处)折叠或打开</p>
<p>1 &lt;!-- 配置切换数据源Key的拦截器 --&gt;</p>
<p>2 &lt;bean id="dataSourceInterceptor" class="com.zjrodger.pub.datasource.DataSourceInterceptor"/&gt;</p>
<p>(5)利用AOP,配置控制数据源在特定条件下切换的切面(关键,重要)。</p>
<p>注意要添加aop名字空间。</p>
<p>配置Spring事务切面和自定义切面类,动态切换数据源,注意两切面的执行顺序。</p>
<p>点击(此处)折叠或打开</p>
<p>&lt;!-- 1.配置Spring框架自身提供的切面类 --&gt;</p>
<p>&lt;tx:advice id="userTxAdvice" transaction-manager="transactionManager"&gt;</p>
<p>&nbsp; &nbsp; &lt;tx:attributes&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="delete*" propagation="REQUIRED" read-only="false"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="insert*" propagation="REQUIRED" read-only="false"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rollback-for="java.lang.Exception" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="update*" propagation="REQUIRED" read-only="false"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rollback-for="java.lang.Exception" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="find*" propagation="SUPPORTS" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="get*" propagation="SUPPORTS" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="select*" propagation="SUPPORTS" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/tx:attributes&gt;</p>
<p>&lt;/tx:advice&gt;</p>
<p>&lt;!-- 2.配置用户自定义的切面,用于切换数据源Key --&gt;</p>
<p>&lt;bean id="dataSourceInterceptor" class="com.zjrodger.pub.datasource.DataSourceInterceptor"&gt;&lt;/bean&gt;&nbsp;</p>
<p>&lt;!-- 3.(重要)配置Spring事务切面和自定义切面类,动态切换数据源,注意两切面的执行顺序 --&gt;</p>
<p>&lt;aop:config&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- (1) Spring框架自身提供的切面 --&gt;</p>
<p>&nbsp; &nbsp; &lt;aop:advisor advice-ref="userTxAdvice" pointcut="execution(public * com.zjrodger.*.service..*.*(..))" order="2"/&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- (2) 用户自定义的切面,根据切入点,动态切换数据源。 --&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;aop:<a href="https://www.2cto.com/kf/web/asp/" target="_blank" class="keylink">asp</a>ect id="dataSourceAspect" ref="dataSourceInterceptor" order="1"&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:before method="setdataSourceBakDb" pointcut="execution(* com.zjrodger.bakdata.service..*.*(..))"/&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:before method="setdataSourceTestDb" pointcut="execution(* com.zjrodger.datatobank.service..*.*(..))"/&gt;</p>
<p>&nbsp; &nbsp; &lt;/aop:aspect&gt;&nbsp;</p>
<p>&lt;/aop:config&gt;</p>
<p>5.1) 注意:</p>
<p>A.注意上述两个切面中的order属性的配置。</p>
<p>B.自定义切面类和Spring自带事务切面类(即元素)的执行的先后顺序要配置正确,否则就会导致导致数据源不能动态切换。</p>
<p>&nbsp; &nbsp; 在AOP中,当执行同一个切入点时,不同切面的执行先后顺序是由“每个切面的order属性”而定的,order越小,则该该切面中的通知越先被执行。</p>
<p>上述元素中,引用了两个切面类:“userTxAdvice类”和“dataSourceAspect类”,其中是Spring框架自定义的切面标签。</p>
<p>根据两个切面类order属性的定义,当程序执行时并且触发切入点后(即调用com.zjrodger.bakdata.service包及其子包下的方法),dataSourceAspect切面类中的setdatasourceBakDb()方通知法首先执行,之后才会执行userTxAdvice事务类中的相关通知方。</p>
<p>5.2) 配置文件作用说明</p>
<p>切面类“DataSourceInterceptor”中有两个方法:setdataSourceTestDb()方法和setdataSourceBakDb()。</p>
<p>1)当用户调用“com.zjrodger.bakdata.service”包及其子包下的方法X“之前”,系统会首先去调用setdataSourceBakDb()方法,设置当前数据源为bakDb的数据源,之后再去调用方法X。</p>
<p>2)当用户调用“com.zjrodger.datatobank.service”或者“com.zjrodger.zxtobank.service”包及其子包下的方法Y之前,系统会首先去调调用setdataSourceTestDb()方法,设置当前的数据源为testDb数据库的数据源,之后再去调用方法Y。</p>
<p>(6)完整的Spring配置文档</p>
<p>点击(此处)折叠或打开</p>
<p>&lt;?xml version="1.0" encoding="UTF-8"?&gt;</p>
<p>&lt;beans xmlns="https://www.springframework.org/schema/beans"</p>
<p>&nbsp; &nbsp; xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xmlns:context="https://www.springframework.org/schema/context"</p>
<p>&nbsp; &nbsp; xmlns:tx="https://www.springframework.org/schema/tx" xmlns:aop="https://www.springframework.org/schema/aop"</p>
<p>&nbsp; &nbsp; xmlns:p="https://www.springframework.org/schema/p" xmlns:m<a href="https://www.2cto.com/kf/ware/vc/" target="_blank" class="keylink">vc</a>="https://www.springframework.org/schema/mvc"</p>
<p>&nbsp; &nbsp; xmlns:task="https://www.springframework.org/schema/task"</p>
<p>&nbsp; &nbsp; xsi:schemaLocation="https://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; https://www.springframework.org/schema/task https://www.springframework.org/schema/task/spring-task.xsd</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; https://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; https://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; https://www.springframework.org/schema/tx https://www.springframework.org/schema/tx/spring-tx.xsd"&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 该配置为自动扫描配置的包下所有使用@Controller注解的类 --&gt;</p>
<p>&nbsp; &nbsp; &lt;context:component-scan base-package="com.zjrodger" /&gt;</p>
<p>&nbsp; &nbsp; &lt;bean id="propertyConfigurer"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="location"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;value&gt;classpath:properties/dbconfig.properties&lt;/value&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="fileEncoding" value="utf-8" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- 备份库数据库数据源 --&gt;</p>
<p>&nbsp; &nbsp; &lt;bean id="c3p0DataSource4BakDb" class="com.mchange.v2.c3p0.ComboPooledDataSource"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; destroy-method="close" depends-on="propertyConfigurer"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="driverClass" value="${bakdb.jdbc.driverclass}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="jdbcUrl" value="${bakdb.jdbc.url}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="user" value="${bakdb.jdbc.username}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="password" value="${bakdb.jdbc.password}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="initialPoolSize" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 连接池中保留的最小连接数。 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="minPoolSize" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 连接池中保留的最大连接数。Default: 15 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="maxPoolSize" value="100" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="acquireIncrement" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 最大空闲时间,10秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="maxIdleTime" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="maxStatements" value="0" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 连接池用完时客户调用getConnection()后等待获取连接的时间,单位:毫秒。超时后会抛出 SQLEXCEPTION,如果设置0,则无限等待。Default:0 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="checkoutTimeout" value="30000" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!--Test数据库数据源 --&gt;</p>
<p>&nbsp; &nbsp; &lt;bean id="c3p0DataSource4TestDb" class="com.mchange.v2.c3p0.ComboPooledDataSource"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; destroy-method="close" depends-on="propertyConfigurer"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="driverClass" value="${jdbc.driverclass}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="jdbcUrl" value="${jdbc.url}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="user" value="${jdbc.username}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="password" value="${jdbc.password}" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="initialPoolSize" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 连接池中保留的最小连接数。 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="minPoolSize" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 连接池中保留的最大连接数。Default: 15 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="maxPoolSize" value="100" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="acquireIncrement" value="5" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 最大空闲时间,10秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="maxIdleTime" value="10" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="maxStatements" value="0" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 连接池用完时客户调用getConnection()后等待获取连接的时间,单位:毫秒。超时后会抛出 SQLEXCEPTION,如果设置0,则无限等待。Default:0 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="checkoutTimeout" value="30000" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- 配置可以存储多个数据源的Bean --&gt;</p>
<p>&nbsp; &nbsp; &lt;bean id="dataSource" class="com.zjrodger.pub.datasource.DynamicDataSource"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="targetDataSources"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;map key-type="java.lang.String"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;entry key="dataSourceKey4TestDb" value-ref="c3p0DataSource4TestDb" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;entry key="dataSourceKey4BakDb" value-ref="c3p0DataSource4BakDb" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/map&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="defaultTargetDataSource" ref="c3p0DataSource4TestDb" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- &lt;property name="dataSource" ref="c3p0DataSource" /&gt; --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="dataSource" ref="dataSource" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="mapperLocations" value="classpath*:com/zjrodger/**/dao/xml/*.xml" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 添加分页插件 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="plugins"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;list&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;bean class="com.github.pagehelper.PageHelper"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="properties"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;props&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="dialect"&gt;mysql&lt;/prop&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="offsetAsPageNum"&gt;true&lt;/prop&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="rowBoundsWithCount"&gt;true&lt;/prop&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="pageSizeZero"&gt;true&lt;/prop&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;prop key="reasonable"&gt;true&lt;/prop&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/props&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/bean&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;/list&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/property&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;</p>
<p>&nbsp; &nbsp; &lt;bean id="transactionManager"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; class="org.springframework.jdbc.datasource.DataSourceTransactionManager"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- &lt;property name="dataSource" ref="c3p0DataSource" /&gt; --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="dataSource" ref="dataSource" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 注解驱动,使spring的controller全部生效 --&gt;</p>
<p>&nbsp; &nbsp; &lt;mvc:annotation-driven /&gt;</p>
<p>&nbsp; &nbsp; &lt;!-- 注解驱动,是spring的task全部生效 --&gt;</p>
<p>&nbsp; &nbsp; &lt;task:annotation-driven /&gt;</p>
<p>&nbsp; &nbsp; &lt;aop:aspectj-autoproxy expose-proxy="true" /&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;tx:annotation-driven transaction-manager="transactionManager"/&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- Spring声明式事务切面 --&gt;</p>
<p>&nbsp; &nbsp; &lt;tx:advice id="userTxAdvice" transaction-manager="transactionManager"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:attributes&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="delete*" propagation="REQUIRED" read-only="false"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rollback-for="java.lang.Exception" no-rollback-for="java.lang.RuntimeException"/&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="insert*" propagation="REQUIRED" read-only="false"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rollback-for="java.lang.Exception" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="update*" propagation="REQUIRED" read-only="false"</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; rollback-for="java.lang.Exception" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="find*" propagation="SUPPORTS" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="get*" propagation="SUPPORTS" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;tx:method name="select*" propagation="SUPPORTS" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/tx:attributes&gt;</p>
<p>&nbsp; &nbsp; &lt;/tx:advice&gt;</p>
<p>&nbsp; &nbsp; &lt;aop:config&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- Spring框架自身提供的切面 --&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:advisor advice-ref="userTxAdvice" pointcut="execution(public * com.zjrodger.*.service..*.*(..))" order="2"/&gt;&nbsp;</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;!-- 用户自定义的切面,根据切入点,动态切换数据源。 --&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:aspect id="dataSourceAspect" ref="dataSourceInterceptor" order="1"&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:before method="setdataSourceBakDb" pointcut="execution(* com.zjrodger.bakdata.service..*.*(..))"/&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:before method="setdataSourceTestDb" pointcut="execution(* com.zjrodger.datatobank.service..*.*(..))"/&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &lt;aop:before method="setdataSourceTestDb" pointcut="execution(* com.zjrodger.zxtobank.service..*.*(..))"/&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;/aop:aspect&gt;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;/aop:config&gt;</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- 配置切换数据源Key的拦截器 --&gt;</p>
<p>&nbsp; &nbsp; &lt;bean id="dataSourceInterceptor" class="com.zjrodger.pub.datasource.DataSourceInterceptor"&gt;&lt;/bean&gt;&nbsp;</p>
<p>&nbsp; &nbsp;&nbsp;</p>
<p>&nbsp; &nbsp; &lt;!-- mybatis配置 --&gt;</p>
<p>&nbsp; &nbsp; &lt;bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="basePackage" value="com.zjrodger.pub.dao,com.zjrodger.zxtobank.dao,com.zjrodger.bakdata.dao" /&gt;</p>
<p>&nbsp; &nbsp; &nbsp; &nbsp; &lt;property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /&gt;</p>
<p>&nbsp; &nbsp; &lt;/bean&gt;&nbsp;</p>
<p>&lt;/beans&gt;</p>
<p>至此,MyBatis多数据源的配置完毕,之后在自己的环境下进行测试,结果测试通过。</p>
<p>要特别注意自定义AOP切面与Spring自带的事务切面的执行顺序,即注意中的配置部分,否则,很容易会出现动态切换数据源失败的现象。</p>
          

本文由职坐标整理并发布,希望对同学们学习MySQL有所帮助,更多内容请关注职坐标数据库MySQL数据库频道!

本文由 @小标 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程