前言:通过liunx创建了两个数据库,所以jdbc里的localhost是linux的ip地址
jdbc的配置:
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/unms?serverTimezone=Asia/Shanghai
jdbc.username=rep
jdbc.password=rep
jdbc.driver2=com.mysql.cj.jdbc.Driver
jdbc.url2=jdbc:mysql://localhost:3306/unms?serverTimezone=Asia/Shanghai
jdbc.username2=rep
jdbc.password2=rep
mybatis的配置:
注:(配置 Spring 和 Mybatis 的整合和事务控制里的ref是控制数据源的id)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
">
<!--当前配置文件的核心内容:1、数据源;2、与mybatis的整合;3、事务控制-->
<!-- 开启注解扫描 -->
<context:component-scan base-package="com.zyl.crm">
<!-- 这里不扫描控制器, 控制器的扫描我们放在SpringMVC中。 -->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
<!-- 引入外部属性文件(数据库连接信息) -->
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<!-- 数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 第二个数据源-->
<bean id="dataSourcetwo" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver2}"></property>
<property name="url" value="${jdbc.url2}"></property>
<property name="username" value="${jdbc.username2}"></property>
<property name="password" value="${jdbc.password2}"></property>
</bean>
<!-- 配置指定的数据源 -->
<bean id="dynamicDataSource" class="com.zyl.crm.util.DynamicDataSource">
<!--默认数据源 -->
<property name="defaultTargetDataSource" ref="dataSource"/>
<property name="targetDataSources">
<map key-type="java.lang.String">
<entry key="dataSource" value-ref="dataSource"/>
<entry key="dataSourcetwo" value-ref="dataSourcetwo"/>
</map>
</property>
</bean>
<bean id="dataSourceAspect" class="com.zyl.crm.util.DataSwitchAop" />
<aop:config>
<aop:aspect ref="dataSourceAspect" >
<!-- 拦截所有service方法 -->
<!--我这里实在service上面加的注解,可自行调换 -->
<aop:pointcut id="dataSourcePointcut" expression="execution(* com.zyl.crm.service..*.*(..))"/>
<aop:before pointcut-ref="dataSourcePointcut" method="intercept" />
</aop:aspect>
</aop:config>
<!--启动对@AspectJ注解的支持 , proxy-target-class设置为true表示通知spring使用cglib而不是jdk的来生成代理方法,这样AOP可以拦截到Controller -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!--配置指定的类-->
<!--<bean id="dataSources" class= "com.zyl.crm.util.DynamicDataSource">
<!– 这里可以指定默认的数据源–>
<property name="defaultTargetDataSource" ref="dataSource"></property>
<property name ="targetDataSources">
<map key-type="java.lang.String">
<!–指定LookupKey和与之对应的数据源,这里的key可以自行定义,要切换数据库的时候以key为标识,不要写错 –>
<entry key="dataSource" value-ref="dataSource"></entry>
<entry key="dataSourcetwo" value-ref="dataSourcetwo"></entry>
</map>
</property>
</bean>-->
<!-- 配置 Spring 和 Mybatis 的整合 -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--指定mybatis全局配置文件路径-->
<property name="configLocation" value="classpath:mybatis-config.xml"></property>
<property name="dataSource" ref="dynamicDataSource"></property>
<!--指定mybatis的mapper文件位置-->
<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
</bean>
<!-- DAO接口所在包名,Spring会自动查找其下的类 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.zyl.crm.dao" />
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"></property>
</bean>
<!-- sql会话模版 -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
<constructor-arg ref="sqlSessionFactory"/>
</bean>
<!-- 配置扫描器,将mybatis接口的实现加入到ioc容器中 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 扫描所有的Dao接口的实现 -->
<property name="basePackage" value="com.zyl.crm.dao"></property>
</bean>
<!-- 可以批量执行的SqlSession -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
<constructor-arg name="executorType" value="REUSE"></constructor-arg>
</bean>
<!--事务控制-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<!-- <property name="dataSource" ref="dataSource"></property>-->
<property name="dataSource" ref="dynamicDataSource"></property>
</bean>
<!--开启基于注解的事务-->
<aop:config>
<!--切入点-->
<aop:pointcut id="txPoint" expression="execution(* com.zyl.crm.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPoint"></aop:advisor>
</aop:config>
<!--事务增强-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--所有的方法都是事务方法-->
<tx:method name="*"/>
<!--以get开头的所有方法都是不需要被事务管理的-->
<tx:method name="get*" read-only="true"></tx:method>
</tx:attributes>
</tx:advice>
<!-- 切面-事务管理控制在Service层 -->
<!--<aop:config>
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.zyl.crm.*.service.*Service.*(..))" />
</aop:config>
<context:component-scan
base-package="com.zyl.crm">
<context:exclude-filter type="regex"
expression="com.ssm.core.*.*.controller.*" />
</context:component-scan>-->
</beans>
所需的依赖:
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.2</version>
</dependency>
切换数据源的工具类:
自定义注解:DataSource (后面测试时切换数据源时使用)
import java.lang.annotation.*;
//设置注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.TYPE})
@Documented
public @interface DataSource {
String value() default "";
}
DataSwitchAop类:
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
import com.zyl.crm.util.DynamicDataSourceHolder;
import java.lang.reflect.Method;
public class DataSwitchAop {
/**
* 拦截目标方法,获取由@DataSource指定的数据源标识,设置到线程存储中以便切换数据源
*
* @param point
* @throws Exception
*/
public void intercept(JoinPoint point) throws Exception {
Class<?> target = point.getTarget().getClass();
MethodSignature signature = (MethodSignature) point.getSignature();
// 默认使用目标类型的注解,如果没有则使用其实现接口的注解
for (Class<?> clazz : target.getInterfaces()) {
resolveDataSource(clazz, signature.getMethod());
}
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) {
System.out.println(clazz + ":" + e.getMessage());
}
}
}
DynamicDataSourceHolder 类:
public class DynamicDataSourceHolder {
private static final ThreadLocal<String> dataSourceKey = new InheritableThreadLocal<String>();
public static String getDataSource(){
return dataSourceKey.get();
}
public static void setDataSource(String dataSource){
dataSourceKey.set(dataSource);
}
public static void clearDataSource(){
dataSourceKey.remove();
}
}
DynamicDataSource类:
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.transaction.reactive.AbstractReactiveTransactionManager;
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DynamicDataSourceHolder.getDataSource();
}
}
测试:这是service层的代码
@DataSource(value = "dataSourcetwo")
public Nas tesx(Integer uid) {
Nas nas1 = nasMapper.selectByPrimaryKey(uid);
return nas1;
}
@DataSource(value = "dataSourcetwo")只要改变里面的value值即可,value值对应的是我们想找的数据源