解决多数据源自动切换不成功问题

产生原因

  1. 代理模式中真实对象方法调用方法不会走代理对象,因此类似于@DS注解使用AOP切面进行数据源的切换,在方法调用方法是不会成功的

解决办法

  1. 原理:通过修改本地线程变量中的数据源栈,来进行数据源的切换
  2. 本实例使用@DS,其他动态数据源(自定义动态数据源)逻辑类似
  3. 封装的手动切换数据源工具类
    自定义一个SmallConsumer注解,主要是填充无参回调函数接口
@FunctionalInterface
public interface SmallConsumer {
          
   
    /**
     * 接收方法
     */
    void accept();
    /**
     * 用于递归调用
     * @param after
     * @return
     */
    default SmallConsumer andThen(SmallConsumer after) {
          
   
        Objects.requireNonNull(after);
        return () -> {
          
   
            accept();
            after.accept();
        };
    }
}
    编写手动切换数据源工具类,实际就是操作本地线程变量
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;

@Component
@Slf4j
public class ChooseDsUtil {
          
   
    private final static String masterDB = "master";
    private final static String slaveDB = "slave";
    @Resource
    private ApplicationContext applicationContext;
    /**
     * 手动切换到master执行
     * 例子:chooseDsUtil.masterExec(() -> memberDao.insert(userPo));
     * @param execConsumer
     */
    public void masterExec(SmallConsumer execConsumer) {
          
   
        try {
          
   
            DynamicDataSourceContextHolder.push(masterDB);
            execConsumer.accept();
        } finally {
          
   
            DynamicDataSourceContextHolder.poll();
        }
    }
    /**
     * 手动切换到slave执行
     * 例子:chooseDsUtil.slaveExec(() -> getUserById("1"));
     * @param execConsumer
     */
    public void slaveExec(SmallConsumer execConsumer) {
          
   
        try {
          
   
            DynamicDataSourceContextHolder.push(slaveDB);
            execConsumer.accept();
        } finally {
          
   
            DynamicDataSourceContextHolder.poll();
        }
    }
    /**
     * 使用AOP的方式进行自动切换,通过获取aop的bean来防止方法调用方法而跳过aop
     * 例子:chooseDsUtil.getAopBean(this.getClass()).B(userPo);,使用B方法的@DS,进行数据源自动切换
     * @return
     */
    public <T> T getAopBean(Class<T> tClass) {
          
   
        return applicationContext.getBean(tClass);
    }
}
  1. 注意:不管是自动切换数据源还是手动切换数据源,切换执行完毕后都不会自动切换回来,比如:在更新逻辑中,先切换到读库进行数据获取,然后再数据处理,最后将处理后的数据更新到写库中,此时在写之前需要切换数据源到写库
经验分享 程序员 微信小程序 职场和发展