Skip to content

多数据源切换

多数据源框架功能介绍 多数据源框架官方文档: dynamic-datasource文档

简介

dynamic-datasource-spring-boot-starter 是一个基于springboot的快速集成多数据源的启动器。

  • 其支持 Jdk 1.7+, SpringBoot 1.5.x 2.x.x 3.x.x。

  • JPA用户不建议使用,JPA自带事务,无法连续切库。

  • 特性

  • 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。

  • 支持数据库敏感配置信息 加密(可自定义) ENC()。

  • 支持每个数据库独立初始化表结构schema和数据库database。

  • 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。

  • 支持 自定义注解 ,需继承DS(3.2.0+)。

  • 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。

  • 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。

  • 提供 自定义数据源来源 方案(如全从数据库加载)。

  • 提供项目启动后 动态增加移除数据源 方案。

  • 提供Mybatis环境下的 纯读写分离 方案。

  • 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。

  • 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。

  • 提供 基于seata的分布式事务方案 。

  • 提供 本地多数据源事务方案。

切换数据源

使用 @DS 切换数据源

注解结果
没有@DS默认数据源
@DS("dsName")dsName可以为组名也可以为具体某个库的名称
java
@Service
@DS("slave")
public class UserServiceImpl implements UserService {

  @Autowired
  private JdbcTemplate jdbcTemplate;

  public List selectAll() {
    return  jdbcTemplate.queryForList("select * from user");
  }
  
  @Override
  @DS("slave_1")
  public List selectByCondition() {
    return  jdbcTemplate.queryForList("select * from user where age >10");
  }
}

配置数据库

常见问题

问:DS放在哪里合适? DS作为切换数据源核心注解,我应该把他注解在哪里合适?这其实是初次接触多数据源的人常问的问题。 这其实没有一定的要求,只是有一些经验之谈。

首先开发者要了解的基础知识是,DS注解是基于AOP的原理实现的,aop的常见失效场景应清楚。 比如内部调用失效,shiro代理失效。 具体见切换数据源失败。

作者通常建议DS放在serviceImpl的方法上,如事务注解一样。

注解在Controller的方法上或类上 并不是不可以,作者并不建议的原因主要是controller主要作用是参数的检验等一些基础逻辑的处理,这部分操作常常并不涉及数据库。

注解在service的实现类的方法或类上 这是作者建议的方式,service主要是对业务的处理, 在复杂的场景涉及连续切换不同的数据库。 如果你的方法有通用性,其他service也会调用你的方法。 这样别人就不用重复处理切换数据源。

注解在mapper上 通常如果你某个Mapper对应的表只在确定的一个库,也是可以的。 但是建议只注解在Mapper的类上。

接口放行

配置文件放行

  • 将需要放行的接口添加到下面即可

  • 具体的代码实现

注解放行

建议使用 @SaIgnore 忽略注解

@SaIgnore

支持在类或方法上放行 注意: 动态路径会解析成通配符 请设计好接口路径避免问题

例如: /get/{userId} 会解析成 /get/*

  • @Salgnore 修饰方法时代表这个方法可以被游客访问,修饰类时代表这个类中的所有接口都可以游客访问。
  • @Salgnore 具有最高优先级,当 @Salgnore 和其它鉴权注解一起出现时,其它鉴权注解都将被忽略。

非数据库字段

  • MybatisPlus 的注解 @TableField(exist = false)
  • 此功能主要发生在,实体类的属性,对应的在数据库没有此此字段,需要增加一个注解解决

字典翻译

  • 此功能主要是将一个属性由数据的值翻译成字典的名称
  • 例如字典中有一个性别字段: SYS_SEX (0:保密 1:男2:女)
  • Vo的实体类对应的字段添加 @Dict("SYS_SEX")
  1. 添加前
json
{
  "sex":"1"
}
  1. 添加后
json
{
  "sex":"男"
}

数据脱敏

系统使用 Jackson 序列化策略 对标注了 Sensitive 注解的属性进行脱敏处理

  • 实体类添加一下注解
java
    // 手机号
    @SensitivityEncrypt(type = SensitivityTypeEnum.PHONE)
    private String phoneNumber;
  • 其他脱敏类型请看 SensitivityTypeEnum.java 枚举类

获取请求IP

在好多的业务场景,我们需要记录请求者的访问真实IP,或者知道哪个区域的这些信息,特此封装了一个简单的工具类

java
    /**
     * 请求
     */
    @GetMapping("/request")
    @SaIgnore
    public String request(HttpServletRequest request){
        // 获取真实的访问IP(需要真实的外网请求,本地无效)
        String ip =  IPUtil.getIp(request);
        log.info("ip:{}",ip);
        // 219.145.7.79
        
        // 依据 ip2region 解析IP获得物理位置
        String cityInfo = AddressUtil.getCityInfo(ip);
        log.info("cityInfo:{}",cityInfo);
        //中国|陕西省|西安市|电信
        return "ok";
    }

Released under the MIT License.