mybatis多数据源配置

本篇博客将演示使用spring+mybatis实现多数据源的配置,实现原理采用aop切面。开始学习前可以先搭建好spring+mybatis的工程。

1.编写数据库配置文件 db.properties

#============================================================================
# 数据源01
#============================================================================
jdbc.one.driver=oracle.jdbc.driver.OracleDriver
jdbc.one.url=jdbc:oracle:thin:@127.0.0.1:1521:w1
jdbc.one.username=system
jdbc.one.password=123456

#============================================================================
#  数据源02
#============================================================================
jdbc.two.driver=com.mysql.jdbc.Driver
jdbc.two.url=jdbc:mysql://127.0.0.1:3306/hy?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
jdbc.two.username=root
jdbc.two.password=123456

#============================================================================
#  数据源03
#============================================================================
jdbc.three.driver=com.mysql.jdbc.Driver
jdbc.three.url=jdbc:mysql://127.0.0.1:3306/webcen?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true
jdbc.three.username=root
jdbc.three.password=123456


#============================================================================
# 通用配置
#============================================================================
jdbc.initialSize=5
jdbc.minIdle=5
jdbc.maxIdle=20
jdbc.maxActive=100
jdbc.maxWait=100000
jdbc.defaultAutoCommit=false
jdbc.removeAbandoned=true
jdbc.removeAbandonedTimeout=600
jdbc.testWhileIdle=true
jdbc.timeBetweenEvictionRunsMillis=60000
jdbc.numTestsPerEvictionRun=20
jdbc.minEvictableIdleTimeMillis=300000

以上配置就不多说了。数据源01使用的是oracle数据源,数据源02、数据源03使用的是mysql数据源

2.编写 applicationContext-dao.xml 

在代码块的注释中有详细描述配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
	">

	<!-- mybatis.spring自动映射 (扫描的是mybatis的mapper及xml) -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.me.dao"/>
	</bean>
	<!-- properties配置文件扫描 (扫描的是配置文件) -->
	<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="locations"> <!-- PropertyPlaceholderConfigurer类中有个locations属性,接收的是一个数组,即我们可以在下面配好多个properties文件 -->
			<array>  <!-- 也可以使用通配符的配置方式 -->
				<value>classpath:properties/*.properties</value>
			</array>
		</property>
	</bean>
	<!-- 第一个数据源dataSourceOne (自动到配置文件中取值填入)-->
	<bean id="dataSourceOne" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${jdbc.one.driver}"/>
		<property name="url" value="${jdbc.one.url}"/>
		<property name="username" value="${jdbc.one.username}"/>
		<property name="password" value="${jdbc.one.password}"/>
		<property name="initialSize" value="${jdbc.initialSize}"/>
		<property name="minIdle" value="${jdbc.minIdle}"/>
		<property name="maxIdle" value="${jdbc.maxIdle}"/>
		<property name="maxActive" value="${jdbc.maxActive}"/>
		<property name="maxWait" value="${jdbc.maxWait}"/>
		<property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}"/>
		<property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
		<property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
		<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
		<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
		<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}"/>
		<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
	</bean>
	<!-- 第二个数据源dataSourceTwo -->
	<bean id="dataSourceTwo" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${jdbc.two.driver}"/>
		<property name="url" value="${jdbc.two.url}"/>
		<property name="username" value="${jdbc.two.username}"/>
		<property name="password" value="${jdbc.two.password}"/>
		<property name="initialSize" value="${jdbc.initialSize}"/>
		<property name="minIdle" value="${jdbc.minIdle}"/>
		<property name="maxIdle" value="${jdbc.maxIdle}"/>
		<property name="maxActive" value="${jdbc.maxActive}"/>
		<property name="maxWait" value="${jdbc.maxWait}"/>
		<property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}"/>
		<property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
		<property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
		<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
		<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
		<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}"/>
		<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
	</bean>
	<!-- 第三个数据源dataSourceThree -->
	<bean id="dataSourceThree" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
		<property name="driverClassName" value="${jdbc.three.driver}"/>
		<property name="url" value="${jdbc.three.url}"/>
		<property name="username" value="${jdbc.three.username}"/>
		<property name="password" value="${jdbc.three.password}"/>
		<property name="initialSize" value="${jdbc.initialSize}"/>
		<property name="minIdle" value="${jdbc.minIdle}"/>
		<property name="maxIdle" value="${jdbc.maxIdle}"/>
		<property name="maxActive" value="${jdbc.maxActive}"/>
		<property name="maxWait" value="${jdbc.maxWait}"/>
		<property name="defaultAutoCommit" value="${jdbc.defaultAutoCommit}"/>
		<property name="removeAbandoned" value="${jdbc.removeAbandoned}"/>
		<property name="removeAbandonedTimeout" value="${jdbc.removeAbandonedTimeout}"/>
		<property name="testWhileIdle" value="${jdbc.testWhileIdle}"/>
		<property name="timeBetweenEvictionRunsMillis" value="${jdbc.timeBetweenEvictionRunsMillis}"/>
		<property name="numTestsPerEvictionRun" value="${jdbc.numTestsPerEvictionRun}"/>
		<property name="minEvictableIdleTimeMillis" value="${jdbc.minEvictableIdleTimeMillis}"/>
	</bean>
	<!-- 使用自己实现的数据源实现类MultipleDataSource,这个类随意放在哪个包下都行 -->
	<bean id="multipleDataSource" class="com.me.po.MultipleDataSource">
		<!-- 设置默认的数据源 (这里将dataSourceOne设置为默认数据源) -->
		<property name="defaultTargetDataSource" ref="dataSourceOne"/>
		<property name="targetDataSources">
			<map>
				<!-- 这个key是对应数据源的别称,通过这个key可以找到对应的数据源,value-ref就是上面数据源的id -->
				<entry key="dataSourceOneKey" value-ref="dataSourceOne"/>
				<entry key="dataSourceTwoKey" value-ref="dataSourceTwo"/>
				<entry key="dataSourceThreeKey" value-ref="dataSourceThree"/>
			</map>
		</property>
	</bean>
	<!-- 让spring使用我们配置的多数据源 -->
	<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="multipleDataSource"/>
	</bean>



	<!--配置事务管理器 (默认配置了所有的方法都使用事务管理,可根据需要进行修改)-->
	<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="multipleDataSource"/>
	</bean>
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="save*" propagation="REQUIRED" rollback-for="Exception"/>
			<tx:method name="*"  propagation="REQUIRED" rollback-for="Exception"/>
		</tx:attributes>
	</tx:advice>
	<!-- AOP配置(事务控制) -->
	<aop:config>
		<!--pointcut元素定义一个切入点,execution中的第一个星号 用以匹配方法的返回类型, 这里星号表明匹配所有返回类型。 com.me.service.*..*(..))表明匹配com.me.service包下的所有类的所有方法 -->
		<aop:pointcut id="myPointcut"
					  expression="execution(* com.me.service.*..*(..))"/>
		<!--将定义好的事务处理策略应用到上述的切入点 -->
		<aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
	</aop:config>
	
</beans>

3.编写三个接口,它们分别代表不同的数据源

package com.me.service;

public interface Datasource01 {
}
package com.me.service;

public interface Datasource02 {
}

 

package com.me.service;

public interface Datasource03 {
}

有人会问,写着东西干啥?不着急,我们看看后面的就知道了 (〃'▽'〃)

 

4.编写我们的多数据源管理类

/**
 * 多数据源java实现
 */
public class MultipleDataSource extends AbstractRoutingDataSource {
    private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();

    public static void setDataSourceKey(String dataSource) {
        dataSourceKey.set(dataSource);
    }

    @Override
    protected Object determineCurrentLookupKey() {
        return dataSourceKey.get();
    }
}
/**
 * 数据库链接自动切换AOP处理
 * Order优先级设置到最高,因为在所有service方法调用前都必须把数据源确定
 * Order数值越小优先级越高
 */
@Component
@Aspect
@Order(1)
public class MultipleDataSourceAspectAdvice {

    private static final Logger LOGGER = Logger.getLogger(MultipleDataSourceAspectAdvice.class);
    public MultipleDataSourceAspectAdvice() {
        LOGGER.info("MultipleDataSourceAspectAdvice 加载成功");
    }

    /**
     * 定义切面
     */
    @Pointcut("execution(* com.me.service.*..*(..))")
    public void pointCut() {
    }    // dataSourceOneKey    // dataSourceTwoKey    // dataSourceThreeKey

    @Around("pointCut()")
    public Object doAround(ProceedingJoinPoint jp) throws Throwable {
        if (jp.getTarget() instanceof Datasource01) {
            System.out.println("使用了数据源01");
            LOGGER.debug("使用数据库链接:dataSourceOneKey");
            MultipleDataSource.setDataSourceKey("dataSourceOneKey");
        } else if (jp.getTarget() instanceof Datasource03) {
            LOGGER.debug("使用数据库链接:dataSourceTwoKey");
            MultipleDataSource.setDataSourceKey("dataSourceTwoKey");
        } else if (jp.getTarget() instanceof Datasource02) {
            LOGGER.debug("使用数据库链接:dataSourceThreeKey");
            MultipleDataSource.setDataSourceKey("dataSourceThreeKey");
        } else {            // 默认是dataSourceOneKey
            System.out.println("默认");
            LOGGER.debug("使用数据库链接:dataSourceOneKey");
            MultipleDataSource.setDataSourceKey("dataSourceOneKey");
        }
        return jp.proceed();
    }
}

我们可以发现,在这里我们使用切面的方式,在执行com.me.service下的所有方法前都确定了使用了哪个数据源。而具体使用哪个数据源的判断是根据我的类继承了哪个datasource接口。例如,我现在要在我新写的类中使用数据源01,那么我就要实现DataSource01接口。

@Service
@Transactional("transactionManager")
public class TestCURDImpl implements TestCURD,Datasource01 {

    private static final Logger logger = Logger.getLogger(TestCURDImpl.class);

    @Override
    public String testRequest() {

        return null;
    }
}

 大家可以在service包下创建一个类,按我上面写的方法测试执行以下。测试执行下

我们看日志,发现已经切换到了数据源01。我们是怎么实现切换的呢?注意我们之前编写的配置文件,里面有配置了数据源的管理类:

到这里,我们的多数据源已经完成,可以放心写代码了(~ ̄▽ ̄)~ ,注意不同的数据源实现不同的接口! 

总结:

   为了方便大家的理解,上面我把配置文件先写在了前面,会和总结的有所不同。 总结如下:我们首先在配置文件 db.properties 中配置了三个不同的数据源。之后写了三个不同数据源对应的接口 DataSource01,DataSource02,DataSource03。编写了一个多数据源的管理类 :MultipleDataSource,再使用切面MultipleDataSourceAspectAdvice 在执行具体方法前切换数据源。最后在配置文件applicationContext-dao.xml中编写具体配置。后期我会再出springBoot+mybatis的多数据源配置。

    最后不要忘记让spring去初始化我们的applicationContext-dao.xml配置文件及扫描相对应的类。

 

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值