SSM多数据源注解动态切换

最新搭建的博客: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" />&lt;!&ndash; 使用的数据源 &ndash;&gt;-->
        <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

SSM框架是指Spring, SpringMVC和MyBatis的整合框架,它广泛应用于Java Web应用开发。在实际开发中,可能会遇到需要连接多个数据库的情况,这时就需要进行多数据源的配置。以下是使用SSM进行多数据源配置的基本步骤: 1. 引入依赖:在项目的pom.xml文件中添加多数据源所需的依赖。 2. 配置数据源:在Spring配置文件中定义多个数据源。可以使用不同的数据源实现类,如org.apache.commons.dbcp.BasicDataSource或者org.springframework.jdbc.datasource.DriverManagerDataSource。 3. 配置MyBatis整合:为每个数据源配置SqlSessionFactory,指定对应的Mapper文件位置。 4. 配置事务管理器:为每个数据源配置事务管理器,使用org.springframework.jdbc.datasource.DataSourceTransactionManager。 5. 注入到Service:在Service使用@Qualifier注解来指定不同的数据源。 以下是一个简单的示例配置: ```xml <!-- 第一个数据源 --> <bean id="dataSourceOne" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/db1"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!-- 第二个数据源 --> <bean id="dataSourceTwo" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/db2"/> <property name="username" value="root"/> <property name="password" value="password"/> </bean> <!-- 配置第一个数据源的SqlSessionFactory --> <bean id="sqlSessionFactoryOne" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSourceOne"/> <!-- 映射文件位置 --> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!-- 配置第二个数据源的SqlSessionFactory --> <bean id="sqlSessionFactoryTwo" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="dataSource" ref="dataSourceTwo"/> <!-- 映射文件位置 --> <property name="mapperLocations" value="classpath:mapper/*.xml"/> </bean> <!-- 配置第一个数据源的事务管理器 --> <bean id="transactionManagerOne" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSourceOne"/> </bean> <!-- 配置第二个数据源的事务管理器 --> <bean id="transactionManagerTwo" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSourceTwo"/> </bean> ``` 在Service使用@Qualifier注解来指定使用哪个数据源: ```java @Service public class UserService { @Autowired @Qualifier("sqlSessionFactoryOne") private SqlSessionFactory sqlSessionFactoryOne; // ... } ```
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值