Spring配置多个数据源并实现数据源的动态切换功能

 更新时间:2024年01月31日 16:28:17   作者:苹果树上的你  
这篇文章主要介绍了Spring配置多个数据源并实现数据源的动态切换功能,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧

Java技术迷

1.首先在config.properties文件中配置两个数据库连接的基本数据。这个省略了
2.在spring配置文件中配置这两个数据源:
数据源1

1
2
3
4
5
6
7
8
9
<!-- initialSize初始化时建立物理连接的个数0  maxActive最大连接池数量8 minIdle最小连接池数量0-->
   <bean id="dataSource1" class="com.alibaba.druid.pool.DruidDataSource" scope="singleton">
       <property name="username" value="${jdbc.username}" />
       <property name="password" value="${jdbc.password}" />
       <property name="url" value="${jdbc.url}" />
       <property name="initialSize" value="${jdbc.init}" />
       <property name="maxActive" value="${jdbc.max}" />
       <property name="minIdle" value="${jdbc.min}" />
   </bean>

数据源2

1
2
3
4
5
6
7
8
<bean id="dataSource2" class="com.alibaba.druid.pool.DruidDataSource" scope="singleton">
        <property name="username" value="${jdbc.username2}" />
        <property name="password" value="${jdbc.password2}" />
        <property name="url" value="${jdbc.url2}" />
        <property name="initialSize" value="${jdbc.init2}" />
        <property name="maxActive" value="${jdbc.max2}" />
        <property name="minIdle" value="${jdbc.min2}" />
    </bean>

3.自定义一个数据源类,该类继承 org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource
并重写determineCurrentLookupKey()方法
3.1代码如下

1
2
3
4
5
6
public class RoutingDataSource extends AbstractRoutingDataSource  {
     @Override
     protected Object determineCurrentLookupKey() {
            return DataSourceHolder.getDataSourceType();
     }
}

3.2将该类交由sping管理,其在spring配置文件中配置如下

1
2
3
4
5
6
7
8
9
10
11
<bean id="dataSource" class="com.coe.exp.core.dataSource.RoutingDataSource">
        <!-- 为targetDataSources注入两个数据源 -->
        <property name="targetDataSources">
            <map key-type="java.lang.String">
                <entry key="ds1" value-ref="dataSource1"/>
                <entry key="ds2" value-ref="dataSource2"/>
            </map>
        </property>
        <!-- 为指定数据源RoutingDataSource注入默认的数据源-->
         <property name="defaultTargetDataSource" ref="dataSource1"/>
    </bean>

3.3spring其他的配置如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<!-- MyBatis配置 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!-- 把dataSource注入给sqlSessionFactory -->
        <property name="dataSource" ref="dataSource" />
        <property name="typeAliasesPackage" value="com.coe.exp.core.ent" />
        <!-- 指定mapper.xml的位置 -->
        <property name="mapperLocations" >
                <array>
                    <value>classpath:com/coe/exp/core/xml/**/*.xml</value>
                    <value>classpath:com/coe/exp/xml/**/*.xml</value>
            </array>
        </property>
        <!-- 指定myBatis配置文件的位置 -->
        <property name="configLocation" value="classpath:mybatis/sqlmapconfig.xml" />
    </bean>
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.coe.exp.core.mapper,com.coe.exp.mapper" />
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
    </bean>
    <!-- 配置事务管理器 -->
    <bean id="transactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource" />
    </bean>
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
         <tx:attributes>
             <tx:method name="insert*" propagation="REQUIRED"/>
             <tx:method name="save*" propagation="REQUIRED"/>
             <tx:method name="update*" propagation="REQUIRED"/>
             <tx:method name="delete*" propagation="REQUIRED"/>
             <tx:method name="remove*" propagation="REQUIRED"/>
             <tx:method name="add*" propagation="REQUIRED"/>
             <tx:method name="find*" propagation="SUPPORTS"/>
             <tx:method name="get*" propagation="SUPPORTS"/>
         </tx:attributes>
     </tx:advice>
     <aop:config>
         <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.coe.exp.dao..*Impl.*(..))" order="2"/>
         <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.coe.exp.core.dao..*Impl.*(..))" order="3"/>
     </aop:config>
    <!-- 注解方式配置事物   -->
    <tx:annotation-driven transaction-manager="transactionManager" />
<!-- 引入属性文件 -->
    <context:property-placeholder location="classpath:config.properties" />
    <!-- 自动扫描(自动注入) -->
    <context:component-scan base-package="com.coe.exp,mm" annotation-config="true"> 
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
    <context:component-scan base-package="com.coe,mm"/> 
    <!-- 自动扫描定时任务 -->
    <task:annotation-driven/>
    <!-- spring自动创建代理,植入切面,proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy 
    poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。 -->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
    <import resource="../shiro/spring-shiro.xml"/>

4.编写一个数据源持有类DataSourceHolder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class DataSourceHolder {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<String>();
    /**
     * @Description: 设置数据源类型
     * @param dataSourceType  数据库类型
     * @return void
     * @throws
     */
    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }
    /**
     * @Description: 获取数据源类型
     * @param
     * @return String
     * @throws
     */
    public static String getDataSourceType() {
        return contextHolder.get();
    }
    /**
     * @Description: 清除数据源类型
     * @param
     * @return void
     * @throws
     */
    public static void clearDataSourceType() {
        contextHolder.remove();
    }
}

5.自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.stereotype.Component;
/**
 * 数据源
 *
 * @author llb 2017-03-30
 *
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface DataSource {
    String value() default "";
}

6.动态切换数据源

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import java.lang.reflect.Method;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
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 org.springframework.core.annotation.Order;
import org.springframework.stereotype.Repository;
import com.coe.exp.core.dataSource.DataSourceHolder;
@Order(1)
@Aspect 
@Repository
public class DataSourceAspect {
    @Pointcut("execution(* com..dao..*Impl.*(..))")
    private void anyMethod() { 
    }
    @AfterReturning(value = "anyMethod()", returning = "result"
    public void afterReturning(JoinPoint joinPoint,Object result){
        DataSourceHolder.clearDataSourceType();
    }
    @Before(value="anyMethod()")
    public void before(JoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); 
        Method method = methodSignature.getMethod(); 
        //如果方法体上使用了DataSource注解
        if (method.isAnnotationPresent(DataSource.class)) {
            //获取该方法上的注解名
            DataSource datasource = method.getAnnotation(DataSource.class);
            //将方法体上的注解的值赋予给DataSourceHolder数据源持有类
            DataSourceHolder.setDataSourceType(datasource.value());
        }
    }
}

7.若方法体上没有注解,则都是使用默认数据源,如果有以下注解,则使用指定的数据源

1
2
3
4
5
6
7
8
9
10
/**
     * 查询哲盟数据库中所有状态正常的客户余额
     * @return
     * @author mxl
     * @version 2017年8月16日下午1:30:06
     */
    @DataSource("ds2")
    public List<CustomerBalanceEnt> getAllCustBalanceByZm(){
        return customerBalanceMapper.getAllCustBalanceByZm();
    }

上面这个方法就是使用“ds2”;

到此这篇关于Spring配置多个数据源并实现数据源的动态切换的文章就介绍到这了,更多相关Spring配置多个数据源内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:https://blog.csdn.net/ll535299/article/details/78203634

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

  • springboot+redis实现简单的热搜功能

    springboot+redis实现简单的热搜功能

    这篇文章主要介绍了springboot+redis实现一个简单的热搜功能,通过代码介绍了过滤不雅文字的过滤器,代码简单易懂,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-05-05
  • String的两种初始化方法讲解

    String的两种初始化方法讲解

    今天小编就为大家分享一篇关于String的两种初始化方法讲解,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2019-04-04
  • Spring处理@Async导致的循环依赖失败问题的方案详解

    Spring处理@Async导致的循环依赖失败问题的方案详解

    这篇文章主要为大家详细介绍了SpringBoot中的@Async导致循环依赖失败的原因及其解决方案,文中的示例代码讲解详细,感兴趣的可以学习一下
    2022-07-07
  • StringUtils工具包中字符串非空判断isNotEmpty和isNotBlank的区别

    StringUtils工具包中字符串非空判断isNotEmpty和isNotBlank的区别

    今天小编就为大家分享一篇关于StringUtils工具包中字符串非空判断isNotEmpty和isNotBlank的区别,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 解决Java Calendar类set()方法的陷阱

    解决Java Calendar类set()方法的陷阱

    这篇文章主要介绍了解决Java Calendar类set()方法的陷阱,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Java实现CSV格式转对象

    Java实现CSV格式转对象

    csv全称“Comma-Separated Values”,是一种逗号分隔值格式的文件,常用来存储数据的纯文本格式文件。本文将用Java语言实现CSV转对象,需要的可以参考一下
    2022-06-06
  • 解决Tomcat修改get提交请求乱码问题

    解决Tomcat修改get提交请求乱码问题

    这篇文章主要介绍了Tomcat修改get提交请求乱码问题的解决方案,需要的朋友参考下
    2017-04-04
  • Java中自己如何实现log2(N)

    Java中自己如何实现log2(N)

    这篇文章主要介绍了Java中自己实现log2(N)的方法,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • Java代理模式实例详解【静态代理与动态代理】

    Java代理模式实例详解【静态代理与动态代理】

    这篇文章主要介绍了Java代理模式,结合实例形式详细分析了java静态代理与动态代理模式相关概念、原理、操作技巧与注意事项,需要的朋友可以参考下
    2019-09-09
  • 不可不知道的10个java谎言

    不可不知道的10个java谎言

    这篇文章主要为大家详细介绍了不可不知道的10个java谎言,大家一定要谨慎,需要了解的朋友可以参考一下
    2016-09-09

最新评论