最新搭建的博客:http://www.cnstudio.top/
创建项目就跳过了,自行百度创建SSM项目及一般的配置。
此文章前提是SSM基本配置已经完成,可以连接单数源。
有两种方法,但大致一样,第一种是第一次找到的,但只能在controller层注解,从代码分工来讲,controller不应该处理数据方面的问题,所以第一种方法不推荐,第二种是在service层注解,推荐使用。
方法1
第一步:修改db.properties文件
#driver=com.mysql.jdbc.Driver
jdbc.driver=com.mysql.cj.jdbc.driver
jdbc.url=jdbc:mysql://localhost:3306/
jdbc.dbnameDV = dv
jdbc.dbnameEcharts = echarts
jdbc.params = useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=root
#配置初始化大小、最小、最大
initialSize=0
maxActive=8
minIdle=0
maxIdle=8
#配置获取连接等待超时的时间
maxWait=20000
validationQuery=select 1
#打开PSCache,并且指定每个连接上PSCache的大小
poolPreparedStatements=true
maxPoolPreparedStatementPerConnectionSize=10
#配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
timeBetweenEvictionRunsMillis=60000
#配置一个连接在池中最小生存的时间,单位是毫秒
minEvictableIdleTimeMillis=1800000
其中,标红的为两个不同的数据库名。
第二步:配置db.xml
<?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"
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">
<!-- 加载db.properties文件 -->
<context:property-placeholder location="classpath:mybatis/db.properties"/>
<!-- 配置数据源,用于访问mysql数据库(${}这种写法称为占位符,具体值在运行时使用db.properties文件中配置的值) com.alibaba.druid.pool.DruidDataSource-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}${jdbc.dbnameDV}?${jdbc.params}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialSize" value="${initialSize}"/>
<property name="maxActive" value="${maxActive}"/>
<property name="minIdle" value="${minIdle}"/>
<property name="maxIdle" value="${maxIdle}"/>
<property name="maxWait" value="${maxWait}"/>
<property name="validationQuery" value="${validationQuery}"/>
<property name="poolPreparedStatements" value="${poolPreparedStatements}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}"/>
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="stat"/>
</bean>
<bean id="dataSourceE" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${jdbc.url}${jdbc.dbnameEcharts}?${jdbc.params}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="initialSize" value="${initialSize}"/>
<property name="maxActive" value="${maxActive}"/>
<property name="minIdle" value="${minIdle}"/>
<property name="maxIdle" value="${maxIdle}"/>
<property name="maxWait" value="${maxWait}"/>
<property name="validationQuery" value="${validationQuery}"/>
<property name="poolPreparedStatements" value="${poolPreparedStatements}"/>
<property name="maxPoolPreparedStatementPerConnectionSize" value="${maxPoolPreparedStatementPerConnectionSize}"/>
<property name="timeBetweenEvictionRunsMillis" value="${timeBetweenEvictionRunsMillis}"/>
<property name="minEvictableIdleTimeMillis" value="${minEvictableIdleTimeMillis}"/>
<!-- 配置监控统计拦截的filters -->
<property name="filters" value="stat"/>
</bean>
<!-- 自定义数据源切换类 -->
<bean id="dynamicDataSource" class="com.DV.DataSource.DynamicDataSource">
<!-- 这里可以指定默认的数据源 -->
<property name="defaultTargetDataSource" ref="dataSource" />
<property name="targetDataSources">
<map key-type="java.lang.String">
<!-- 指定lookupKey和与之对应的数据源 -->
<entry key="dataSource" value-ref="dataSource"></entry>
<entry key="dataSourceE" value-ref="dataSourceE"></entry>
</map>
</property>
</bean>
</beans>
其中,标红的为多数据源的切换,上面已经配置了多个数据源,在这指定切换数据源的类,以及数据源。
第三步:在spring-mybatis.xml(spring和mybatis整合配置文件)将数据源指定为多数据源切换的id,即:dynamicDataSource。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!-- 该配置文件是mybatis与spring的整合 -->
<!-- 整合的固定写法,配置SqlSessionFactory -->
<!-- mybatis文件配置,扫描所有mapper.xml文件 -->
<!-- 配置mybatisSqlSessionFactoryBean -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--<property name="dataSource" ref="dataSource" /><!– 使用的数据源 –>-->
<property name="dataSource" ref="dynamicDataSource" /><!-- 使用的数据源 -->
<property name="configLocation" value="classpath:mybatis/mybatis-config.xml" /><!-- mybatis的配置文件 -->
<property name="mapperLocations" value="classpath*:com/DV/dao/xml/*Mapper.xml" /><!-- 自动扫描mapper的xml文件 -->
</bean>
<!-- 配置SqlSessionTemplate -->
<bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>
<!-- 为每个Mapper接口在运行时动态生成实现类 -->
<!-- 配置mybatis mapper接口,扫描所有dao -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.DV.dao.mapper" /><!-- 自动扫描mapper接口,为每个接口生成MapperFactoryBean -->
<property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" /><!-- 如果有多个数据源的话,须指定使用哪一个 -->
</bean>
</beans>
第四步:在事务管理的配置文件中,修改数据源,同上。并加入切面配置
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.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">
<!-- 事务配置可以抽象为四部分:数据源、事务管理器、事务属性、事务代理 -->
<!-- 数据源:支持事务的数据资源,如数据库 -->
<!-- 事务管理器:JDBC事务管理器、EJB容器事务管理器、分布式事务管理器等 -->
<!-- 事务属性:事务的传播属性等 -->
<!-- 事务代理:将事务属性应用到事务目标对象的方法上,且由事务管理器来管理、如自动的提交或回滚事务 -->
<!-- 事务管理 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 对insert,update,delete 开头的方法进行事务管理,只要有异常就回滚 -->
<tx:method name="insert*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
<tx:method name="update*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
<tx:method name="delete*" propagation="REQUIRED" rollback-for="java.lang.Throwable"/>
<!-- select,count开头的方法,开启只读,提高数据库访问性能 -->
<tx:method name="select*" read-only="true"/>
<tx:method name="count*" read-only="true"/>
<!-- 对其他方法 使用默认的事务管理 -->
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="serviceMethods" expression="execution(* com.DV.service..*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="serviceMethods"/>
</aop:config>
<!-- 配置使Spring采用CGLIB代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<!-- 对dataSource 数据源进行事务管理 -->
<!--<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dataSource"/>-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" p:dataSource-ref="dynamicDataSource"/>
<!-- 使用annotation注解方式配置事务,启用对事务注解的支持 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- 切面 -->
<aop:config> <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.DV.service.impl.*.*(..))" /> </aop:config>
</beans>
标红的为注意代码
第五步:在spring-mvc(spring和mvc整合配置文件)中,开启aop,对类代理
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" 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/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">
<context:annotation-config />
<!--注解驱动-->
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
<bean id="fastJsonHttpMessageConverter" class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
<property name="supportedMediaTypes">
<list>
<value>application/json;charset=UTF-8</value>
</list>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<!-- 开启aop,对类代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<bean id="logAopAction" class="com.DV.DataSource.LogAopAction"/>
<!--组件扫描-->
<context:component-scan base-package="com.DV.controller"/>
<!--视图解析-->
<bean id="ViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/jsp/" p:suffix=".jsp"/>
<!--静态资源-->
<mvc:resources mapping="/content/**" location="/WEB-INF/content/"/>
</beans>
标红代码为注意代码
第六步:创建自定义数据源选择器类DynamicDataSource
package com.DV.DataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource 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();
}
}
第七步:自定义注解DataSourceChange
package com.DV.DataSource;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 定义DataSource的注解
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.TYPE})
@Documented
public @interface DataSourceChange {
String dataSource() default "";
}
第八步:前置通知(这里切的是controller)
package com.DV.DataSource;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import java.lang.reflect.Method;
@Aspect
public class LogAopAction {
//配置接入点
@Pointcut("execution(* com.DV.controller..*.*(..))")
private void controllerAspect(){}//定义一个切入点
@Before("controllerAspect()")
public void dataSwitch(JoinPoint joinPoint){
Signature signature = joinPoint.getSignature();
MethodSignature methodSignature =(MethodSignature) signature;
Method method = methodSignature.getMethod();
DataSourceChange data = null;
String dataSource = "";
if(method != null){
data = method.getAnnotation(DataSourceChange.class);
if(data != null){
dataSource = data.dataSource();
if(dataSource != null){
DynamicDataSource.setDataSourceKey(dataSource);
}
}
}
}
}
在conrtoller中的方法上使用:@DataSourceC(dataSource="数据源ID")即可,测试代码如下:
@RequestMapping("test")
@ResponseBody
@DataSourceC(dataSource="dataSourceE")
public List<Map> test(){
List<Map> result = dataGraphService.test();
return result;
}
测试结果如下:
如图,测试通过,可以注解改变数据源。参考文章地址:https://blog.csdn.net/weixin_38897274/article/details/78529940
方法2
1、创建接口DataSource,用于定义注解。
package com.DV.entity;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface DataSource {
String value();
}
2、定义类DynamicDataSource,用于重写AbstractRoutingDataSource以及获取和设置数据源
package com.DV.entity;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSource extends AbstractRoutingDataSource {
public static final ThreadLocal<String> holder = new ThreadLocal<String>();
//设置数据源
public static void setDataSource(String datasource) {
holder.set(datasource);
}
//获取数据源
private String getDataSource() {
return holder.get();
}
//清除数据源
public static void clearDataSource() {
holder.remove();
}
@Override
protected Object determineCurrentLookupKey() {
return getDataSource();
}
}
3、定义类DataSourceAspect,用于AOP切面。
package com.DV.entity;
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.reflect.MethodSignature;
public class DataSourceAspect {
//切换数据源
public void before(JoinPoint point)
{
Object target = point.getTarget();
System.out.println(target.toString());
String method = point.getSignature().getName();
System.out.println(method);
Class<?>[] classz = target.getClass().getInterfaces();
Class<?>[] parameterTypes = ((MethodSignature) point.getSignature())
.getMethod().getParameterTypes();
try {
Method m = classz[0].getMethod(method, parameterTypes);
System.out.println(m.getName());
if (m != null && m.isAnnotationPresent(DataSource.class)) {
DataSource data = m.getAnnotation(DataSource.class);
DynamicDataSource.setDataSource(data.value());
}
} catch (Exception e) {
e.printStackTrace();
}
}
//清除数据源,使用默认数据源
public void after(){
DynamicDataSource.clearDataSource();
}
}
}
4、最后,还需要修改spring-mvc配置文件。
<!-- 开启aop,对类代理 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
<!-- 配置数据库注解aop -->
<bean id="dataSourceAspect" class="com.DV.entity.DataSourceAspect" />
<aop:config>
<aop:aspect id="c" ref="dataSourceAspect">
<aop:pointcut id="tx" expression="execution(* com.DV.service..*.*(..))"/>
<aop:before pointcut-ref="tx" method="before"/>
<aop:after pointcut-ref="tx" method="after"/>
</aop:aspect>
</aop:config>
5、在service方法中使用
package com.DV.service;
import com.DV.entity.DataSource;
import java.util.List;
import java.util.Map;
public interface dataGraphService {
List<Map> echartSet(String corp_id, String type);
@DataSource("Echarts")
List<Map> test();
}
测试可以切换。
参考文章地址:https://blog.csdn.net/wolfjin/article/details/72465668