勇敢的打工人 2024-09-20 16:55 采纳率: 42.9%
浏览 18
已采纳

多数据源与Hystrix的冲突

微服务项目中增加多数据源功能出现与Hystrix冲突的问题

**下图 1图是正常访问从库数据,2图是查询从库数据失败查询成主库了 请问大家怎么样让多数据源兼容Hystrix
**

先看一下问题图片
1、能够正常访问从库的操作 查询从库数据

img

2、错误查询从库Hystrix的注释没去掉 查询出来的数据是主库数据

img

代码部分

    @DataSource("slave") // 指定从库
    @GetMapping("/OperatePopularDoListx")
    @HystrixCommand(fallbackMethod = "OperatePopularDoList")
    public List<OperatePopularDo> OperatePopularDoListx() {
        QueryWrapper wrapper = new QueryWrapper();
        wrapper.eq("STATUS", 0);
        wrapper.orderByDesc("order_num");
        List<OperatePopularDo> list = operatePopularService.list(wrapper);
        return list;
    }

多数据源切换用的是aop去环绕切的代码如下

package com.chinalife.gstc.commons.aop;
import com.alibaba.druid.pool.DruidDataSource;
import com.chinalife.gstc.commons.config.DruidConfig;
import com.chinalife.gstc.commons.datasource.CommonConstant;
import com.chinalife.gstc.commons.datasource.DynamicDataSourceHolder;
import com.chinalife.gstc.commons.utils.SpringUtil;
import com.netflix.hystrix.strategy.concurrency.HystrixRequestContext;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.*;

@Aspect
@Component
@Slf4j
public class DataSourceAspect {
    // 设置DataSource注解的切点表达式
    @Pointcut("execution(public * com.chinalife.gstc.controller..*.*(..))")
    public void dynamicDataSourcePointCut(){
    }
    //环绕通知
    @Around("dynamicDataSourcePointCut()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        DataSource defineAnnotation = getDefineAnnotation(joinPoint);
        HystrixRequestContext context = HystrixRequestContext.initializeContext();
        String key = "";
        //判断方法上是否有注解,没有注解则默认是走的是主服务器
        if (defineAnnotation == null) {
            key = CommonConstant.MASTER;
        }else {
            key = defineAnnotation.value();
        }
        //判断数据库是否断开连接
        key = getConnection(key);
        System.err.println(" 当前使用: "+key);
        DynamicDataSourceHolder.setDynamicDataSourceKey(key);
        Object proceed = null;
        try {
            proceed =  joinPoint.proceed();
        } finally {
            context.shutdown();
            DynamicDataSourceHolder.removeDynamicDataSourceKey();
        }
        return proceed;
    }
    /**
     * 先判断方法的注解,后判断类的注解,以方法的注解为准
     * @param joinPoint
     * @return
     */
    private DataSource getDefineAnnotation(ProceedingJoinPoint joinPoint){
        // 获取访问信息
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        // 获取方法上的注解
        DataSource dataSourceAnnotation = methodSignature.getMethod().getAnnotation(DataSource.class);
        // 方法上无注解则抛空指针 nonNull
        if (Objects.nonNull(dataSourceAnnotation)) {
            return dataSourceAnnotation;
        } else {
            // 获取类上的注解 返回类
            Class<?> dsClass = joinPoint.getTarget().getClass();
            return dsClass.getAnnotation(DataSource.class);
        }
    }
    /**
     * 判断数据库是否连接成功
     * @return
     */
    private String getConnection(String target) throws SQLException {
        //将数据源名称添加到list集合,方便后续操作
        List<String> dataSources = new ArrayList<>();
        dataSources.add(CommonConstant.SLAVE);
        dataSources.add(CommonConstant.MASTER);
        //获取装配好的bean对象
        DruidConfig druidConfig = (DruidConfig) SpringUtil.getBean("druidConfig");
        DruidDataSource druidDataSource = new DruidDataSource();
        if (target.equals(CommonConstant.SLAVE)) {
            druidDataSource = (DruidDataSource) druidConfig.slaveDataSource();
        }
        if (target.equals(CommonConstant.MASTER)) {
            druidDataSource = (DruidDataSource) druidConfig.masterDataSource();
        }
        System.err.println("配置:"+target);
        try {
           Connection connection = DriverManager.getConnection(druidDataSource.getUrl(), druidDataSource.getUsername(), druidDataSource.getPassword());
            if (connection != null && !connection.isClosed()) {
                System.out.println("数据库连接成功!");
            } else {
                System.out.println("数据库连接异常!");
            }
        } catch (SQLException e) {
            System.out.println("数据库连接失败-"+target+":" + e.getMessage());
            dataSources.remove(target);
            // shuffle 打乱顺序
            Collections.shuffle(dataSources);
            // 再选择一个新的数据源
            String changeTarget = dataSources.get(0);
            // 再次尝试连接数据源
            getConnection(changeTarget);
            log.info("========================数据源:{}连接异常,切换数据源为:{}===========================",target,changeTarget);
            return changeTarget;
        }
        log.info("数据源结束");
        return target;
    }
}


  • 写回答

19条回答 默认 最新

  • guicai_guojia 2024-09-20 17:02
    关注

    感觉是mp 的问题 你 把list 方法写到mapper 里 然后数据源 注解直接给到mapper 的方法上

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(18条)

报告相同问题?

问题事件

  • 已采纳回答 9月23日
  • 创建了问题 9月20日

悬赏问题

  • ¥15 如何在vue.config.js中读取到public文件夹下window.APP_CONFIG.API_BASE_URL的值
  • ¥50 浦育平台scratch图形化编程
  • ¥20 求这个的原理图 只要原理图
  • ¥15 vue2项目中,如何配置环境,可以在打完包之后修改请求的服务器地址
  • ¥20 微信的店铺小程序如何修改背景图
  • ¥15 UE5.1局部变量对蓝图不可见
  • ¥15 一共有五道问题关于整数幂的运算还有房间号码 还有网络密码的解答?(语言-python)
  • ¥20 sentry如何捕获上传Android ndk 崩溃
  • ¥15 在做logistic回归模型限制性立方条图时候,不能出完整图的困难
  • ¥15 G0系列单片机HAL库中景园gc9307液晶驱动芯片无法使用硬件SPI+DMA驱动,如何解决?