业务场景问题一:主从库下强制读取主库数据自定义注解@DbForceMaster

本文介绍了在微服务项目中如何通过自定义注解DbForceMaster和相关组件(如拦截器和数据源切换器)来解决主从库读写分离场景下的数据实时性问题,确保业务不受脏数据影响。
摘要由CSDN通过智能技术生成

背景:在微服务或大型项目中,经常会遇到数据库多数据源主从库读写分离的业务场景,架构上设计引发的业务问题就是有些场景下对数据的实时性要求较强,需要实时读取到数据库新增的数据,代码跑的又快,往往主从库的数据增删改操作导致的数据更新还没有及时同步读取了从库的历史数据,导致后续的业务拆分细节出现脏数据。所以,为了解决这部分问题,引入了自定义注解@DbForceMaster(自己定义什么都行)。
具体流程是:

  • 定义自定义注解,命名为DbForceMaster
  • 处理自定义注解,拦截器或者AOP调用
  • 配置多数据源,完成注解的主从数据库切换
  • 代码中引入自定义注解
  1. 首先是创建一个注解类,命名为DbForceMaster

    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface DbForceMaster {
        // 如果需要,可以添加注解属性,默认运行时方法上使用
        boolean flag() default true;
    }
    
  2. 然后就是处理自定义注解,这部分方法就自己定义,用HandlerMethodInterceptor拦截器或者是AOP面向切面编程都行,保证在方法引入@DbForceMaster注解时切换到主库数据源

    @Aspect
    @Component
    public class MasterDatabaseSwitchInterceptor {
    
        @Autowired
        private DataSourceSelector dataSourceSelector; // 假设有一个数据源选择器
    
        @Around("@annotation(DbForceMaster)")
        public Object processWithMaster(ProceedingJoinPoint joinPoint) throws Throwable {
            if (dbForceMaster.flag()) {
                DbForceMasterContextHolder.setForceMasterFlag(true);
            }
            try {
                return joinPoint.proceed();
            } finally {
                DbForceMasterContextHolder.clearForceMasterFlag();
            }
        }
    }
    
  3. 配置多数据源,在项目中配置多个数据源(主从库),并实现一个DataSource切换器,可以基于某种策略选择主库或者从库

    @Configuration
    public class DataSourceConfig {
    
        public static final Integer HASH_MAP_DEFAULT_SIZE = 16;
        
        @Primary // 标记为主数据源
        @Bean(name = "masterDataSource")
        public DataSource masterDataSource() {
            // 配置主库数据源的代码
        }
    
        @Bean(name = "slaveDataSource")
        public DataSource slaveDataSource() {
            // 配置从库数据源的代码
        }
    
        @Bean
        public DataSourceRouter dataSourceRouter(@Qualifier("masterDataSource") DataSource masterDataSource,
                                                @Qualifier("slaveDataSource") DataSource slaveDataSource) {
            // 创建一个数据源路由器,实现切换逻辑
            DynamicDataSource dynamicDataSource = new DynamicDataSource();
            Map<Object, Object> targetDataSources = new HashMap<>(MapConsts.HASH_MAP_DEFAULT_SIZE);
            targetDataSources.put(DataSourceTypeEnum.MASTER.getType(), masterDataSource());
            targetDataSources.put(DataSourceTypeEnum.SLAVE.getType(), slaveDataSource());
            dynamicDataSource.setDefaultTargetDataSource(masterDataSource());
            dynamicDataSource.setTargetDataSources(targetDataSources);
            return dynamicDataSource;
        }
    
        @Bean
        public DataSourceSelector dataSourceSelector(DataSourceRouter dataSourceRouter) {
            return new DataSourceSelector(dataSourceRouter);
        }
    
        // DataSourceSelector 类应实现切换数据源的方法
    }
    
  4. 使用自定义注解,在强制使用主库数据的方法上引入自定义注解@DbForceMaster

    @DbForceMaster
    public Data someMethod() {
        // 此处执行的SQL查询将强制从主库读取数据
        return repository.fetchCriticalData();
    }
    

​ 这只是一个简单的自定义注解设计流程,基本思路就是编辑注解,处理注解,配置数据源和切换机制,使用注解。在微服务nacos项目中使用到了,解决了订单-工单-任务拆解过程中数据读取到了从库的脏数据,没有实时获取新增的主库数据,导致业务测试出现问题。

  • 19
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值