2021-08-31

第一步,db.properties,配置数据源信息

#图个方便,均采用sqlserver
db1.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
db1.url=jdbc:sqlserver://localhost:1433;DatabaseName=db1
db1.username=sa
db1.password=sa

db2.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
db2.url=jdbc:sqlserver://localhost:1433;DatabaseName=db2
db2.username=sa
db2.password=sa

第二步,applicationContext.xml,配置数据源

<!-- 引入数据库配置文件,位置要正确 -->
<context:property-placeholder location="classpath:configs/db.properties"/>
<!--配置db1数据库-->
<bean id="db1DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass"><value>${db1.driver}</value></property>
    <property name="jdbcUrl"><value>${db1.url}</value></property>
    <property name="user"><value>${db1.username}</value></property>
    <property name="password"><value>${db1.password}</value></property>
</bean>
<!--配置db2数据库-->
<bean id="db2DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
    <property name="driverClass"><value>${db2.driver}</value></property>
    <property name="jdbcUrl"><value>${db2.url}</value></property>
    <property name="user"><value>${db2.username}</value></property>
    <property name="password"><value>${db2.password}</value></property>
</bean>

第三步,DynamicDataSource.java,动态切换数据源类

package com.common.aop.dataSource;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import com.common.aop.dataSource.DynamicDataSourceHolder;

public class DynamicDataSource extends AbstractRoutingDataSource{

	@Override
	protected Object determineCurrentLookupKey() {
		//获取当前使用的数据源
        return DynamicDataSourceHolder.getDataSource();
	}

}

第四步,DynamicDataSourceHolder.java,动态切换数据源支持类

package com.common.aop.dataSource;

public class DynamicDataSourceHolder {
	
	//数据源标识保存在线程变量中,避免多线程操作数据源时互相干扰
	private static final ThreadLocal<String> THREAD_DATA_SOURCE = new ThreadLocal<String>(); 
	
	public static final String DATA_SOURCE_DB1 = "db1DataSource";//对应动态数据源配置中的key
    public static final String DATA_SOURCE_DB2 = "db2DataSource";  
  
    public static String getDataSource() {
        return THREAD_DATA_SOURCE.get();
    }

    public static void setDataSource(String dataSource) {
        THREAD_DATA_SOURCE.set(dataSource);
    }

    public static void clearDataSource() {
        THREAD_DATA_SOURCE.remove();
    }
}

第五步,applicationContext.xml,配置动态数据源

<!-- 动态DataSource配置,对应DynamicDataSource-->
<bean id="dynamicDataSource" class="com.common.aop.dataSource.DynamicDataSource">  
	<property name="targetDataSources">  
	    <map key-type="java.lang.String">
	    	<!-- 对应DynamicDataSourceHolder-->
	    	<entry key="db1DataSource" value-ref="db1DataSource"/>
	    	<entry key="db2DataSource" value-ref="db2DataSource"/> 
	    </map>  
	</property>
	<!-- 配置默认数据源 -->
	<property name="defaultTargetDataSource" ref="db1DataSource"/>  
</bean>

<!--整合mybatis-->
<bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <!-- 配置MyBatis全局配置文件的位置 -->
    <property name="configLocation" value="classpath:configs/mybatis-config.xml"></property>
    <!-- 对应动态数据源配置 -->
    <property name="dataSource" ref="dynamicDataSource"></property>
    <!-- 指定mybatis,mapper文件的位置 -->
    <property name="mapperLocations" value="classpath:com/*/*/dao/*.xml"></property>
</bean>
<!-- 配置扫描器,将mybatis接口的实现加入到ioc容器 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
    <!-- 扫描所有dao接口的实现,加入到ioc容器中 -->
    <property name="basePackage" value="com.*.*.dao"></property>
    <property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
</bean>

第六步,MultipleDataSourceAspect.java,aop切换数据源

package com.common.aop.dataSource;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Order(-100) //这是为了保证aop在事务注解之前生效,值越小,优先级越高
public class MultipleDataSourceAspect {

    /**
     * 向db1下的所有实现切入数据源(默认数据源)
     * 根据service层接口实现类区分数据库
     */
    @Pointcut("execution( * com.db1.*.service.*Impl.*(..))")
    public void cutIntoDb1() {}
    @Before(value = "cutIntoDb1()")
    public void beforeCutIntoDb1(JoinPoint joinPoint) {
    	System.out.println("切入db1数据库");
    	DynamicDataSourceHolder.setDataSource(DynamicDataSourceHolder.DATA_SOURCE_DB1);
    }

    
    /**
     * 向db2下的所有实现切入数据源
     */
    @Pointcut("execution( * com.db2.*.service.*Impl.*(..))")
    public void cutIntoDb2() {}
    @Before(value = "cutIntoDb1()")
    public void beforeCutIntoDb1(JoinPoint joinPoint) {
    	System.out.println("切入db2数据库");
    	DynamicDataSourceHolder.setDataSource(DynamicDataSourceHolder.DATA_SOURCE_DB2);
    }
    @After(value = "cutIntoDb2()")
    public void afterCutIntoDb2(JoinPoint point) {
    	//清理掉当前设置的数据源,让默认的数据源不受影响
    	System.out.println("清除db2数据库");
    	DynamicDataSourceHolder.clearDataSource();
    }
}

第七步,applicationContext.xml,配置aop并扫描

<!-- 扫描aop,自动加载MultipleDataSourceAspect-->
<context:component-scan base-package="com.common.aop" />
	
<!-- 开启aop,简化写法,与下面的意思相同 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 启动AOP AspectJ注解自动代理 -->
<!-- <aop:aspectj-autoproxy /> -->
<!-- 通知spring使用cglib而不是jdk的来生成代理方法 AOP可以拦截到Controller -->
<!-- <aop:config proxy-target-class="true"></aop:config> -->

到此,简单配置完成。

目录结构

项目目录结构

参考:https://blog.csdn.net/yybk426/article/details/115123694


版权声明:本文为hsy1079120641原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。