SSM(八)动态切换数据源(下)

本文涉及的产品
云原生内存数据库 Tair,内存型 2GB
云数据库 Redis 版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 在现在开发的过程中应该大多数朋友都有遇到过切换数据源的需求。比如现在常用的数据库读写分离,或者就是有两个数据库的情况,这些都需要用到切换数据源。

接下来的用法相比大家也应该猜到了。


就是在每次调用数据库之前我们都要先通过DataSourceHolder来设置当前的数据源。看下demo:


@Test
    public void selectByPrimaryKey() throws Exception {
        DataSourceHolder.setDataSources(Constants.DATASOURCE_TWO);
        Datasource datasource = dataSourceService.selectByPrimaryKey(7);
        System.out.println(JSON.toJSONString(datasource));
    }


详见我的单测。


使用起来也是非常简单。但是不知道大家注意到没有,这样的做法槽点很多:


  1. 每次使用需要手动切换,总有一些人会忘记写(比如我)。


  1. 如果是后期需求变了,查询其他的表了还得一个个改回来。


那有没有什么方法可以自动的帮我们切换呢?


肯定是有的,大家应该也想得到。就是利用SpringAOP了。


自动切换数据源


首先要定义好我们的切面类DataSourceExchange:


package com.crossoverJie.util;
import org.aspectj.lang.JoinPoint;
/**
 * Function:拦截器方法
 *
 * @author chenjiec
 *         Date: 2017/1/3 上午12:34
 * @since JDK 1.7
 */
public class DataSourceExchange {
    /**
     *
     * @param point
     */
    public void before(JoinPoint point) {
        //获取目标对象的类类型
        Class<?> aClass = point.getTarget().getClass();
        //获取包名用于区分不同数据源
        String whichDataSource = aClass.getName().substring(25, aClass.getName().lastIndexOf("."));
        if ("ssmone".equals(whichDataSource)) {
            DataSourceHolder.setDataSources(Constants.DATASOURCE_ONE);
        } else {
            DataSourceHolder.setDataSources(Constants.DATASOURCE_TWO);
        }
    }
    /**
     * 执行后将数据源置为空
     */
    public void after() {
        DataSourceHolder.setDataSources(null);
    }
}


逻辑也比较简单,就是在执行数据库操作之前做一个切面。


  • 通过JoinPoint对象获取目标对象。


  • 在目标对象中获取包名来区分不同的数据源。


  • 根据不同数据源来进行赋值。


  • 执行完毕之后将数据源清空。


关于一些JoinPoint的API:


package org.aspectj.lang;
import org.aspectj.lang.reflect.SourceLocation;
public interface JoinPoint {
    String toString();         //连接点所在位置的相关信息
    String toShortString();     //连接点所在位置的简短相关信息
    String toLongString();     //连接点所在位置的全部相关信息
    Object getThis();         //返回AOP代理对象
    Object getTarget();       //返回目标对象
    Object[] getArgs();       //返回被通知方法参数列表
    Signature getSignature();  //返回当前连接点签名
    SourceLocation getSourceLocation();//返回连接点方法所在类文件中的位置
    String getKind();        //连接点类型
    StaticPart getStaticPart(); //返回连接点静态部分
}


为了通过包名来区分不同数据源,我将目录结构稍微调整了下:


2

将两个不同的数据源的实现类放到不同的包中,这样今后如果还需要新增其他数据源也可以灵活的切换。


看下Spring的配置:


<bean id="dataSourceExchange" class="com.crossoverJie.util.DataSourceExchange"/>
    <!--配置切面拦截方法 -->
    <aop:config proxy-target-class="false">
        <!--将com.crossoverJie.service包下的所有select开头的方法加入拦截
        去掉select则加入所有方法
        -->
        <aop:pointcut id="controllerMethodPointcut" expression="
        execution(* com.crossoverJie.service.*.select*(..))"/>
        <aop:pointcut id="selectMethodPointcut" expression="
        execution(* com.crossoverJie.dao..*Mapper.select*(..))"/>
        <aop:advisor advice-ref="methodCacheInterceptor" pointcut-ref="controllerMethodPointcut"/>
        <!--所有数据库操作的方法加入切面-->
        <aop:aspect ref="dataSourceExchange">
            <aop:pointcut id="dataSourcePointcut" expression="execution(* com.crossoverJie.service.*.*(..))"/>
            <aop:before pointcut-ref="dataSourcePointcut" method="before"/>
            <aop:after pointcut-ref="dataSourcePointcut" method="after"/>
        </aop:aspect>
    </aop:config>


这是在我们上一篇整合redis缓存的基础上进行修改的。


这样缓存和多数据源都满足了。


实际使用:


@Test
    public void selectByPrimaryKey() throws Exception {
        Rediscontent rediscontent = rediscontentService.selectByPrimaryKey(30);
        System.out.println(JSON.toJSONString(rediscontent));
    }


3

这样看起来就和使用一个数据源这样简单,再也不用关心切换的问题了。


总结


不过按照这样的写法是无法做到在一个事务里控制两个数据源的。这个我还在学习中,有相关经验的大牛不妨指点一下。


项目地址:github.com/crossoverJi…

个人博客地址:crossoverjie.top

GitHub地址:github.com/crossoverJi…


相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
相关文章
|
3月前
|
JavaScript Java 测试技术
基于ssm+vue.js+uniapp小程序的宝鸡文理学院学生成绩动态追踪系统附带文章和源代码部署视频讲解等
基于ssm+vue.js+uniapp小程序的宝鸡文理学院学生成绩动态追踪系统附带文章和源代码部署视频讲解等
31 0
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现1
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现1
52 0
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之1
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之1
53 0
java202304java学习笔记第六十七天-ssm-动态sql-一对一的配置实现2
java202304java学习笔记第六十七天-ssm-动态sql-一对一的配置实现2
55 0
java202304java学习笔记第六十七天-ssm-动态sql-一对一的配置实现2
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之2
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之2
52 0
java202304java学习笔记第六十七天-ssm-动态sql-多对多注解开发之2
java202304java学习笔记第六十七天-ssm-动态sql-知识小结
java202304java学习笔记第六十七天-ssm-动态sql-知识小结
52 0
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置2
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置2
52 0
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置
java202304java学习笔记第六十七天-ssm-动态sql-一对多配置
55 0
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现2
java202304java学习笔记第六十六天-ssm-动态sql-一对一的配置实现2
58 0
java202304java学习笔记第六十七天-ssm-动态sql-一对多得注解开发2
java202304java学习笔记第六十七天-ssm-动态sql-一对多得注解开发2
55 0