baomidou多数据源切换,多线程获取数据源解决方案

问题

编写动态多数据源切换代码时,使用@DS注解加在接口处实现多数据源切换,web端接口一次会话(

HttpServletRequest

)数据源保存在session中,在接口具体实现中难免会遇到异步或者多线程处理表业务,此时遇到多线程获取不到当前数据源的异常。深究发现

DynamicDataSourceContextHolder

保存当前数据源使用ThreadLocal实现的,threadLocal是线程隔离的。导致多线程或者异步无法获取数据源。

解决策略:

        首先,在异步处理时,手动设置当前数据源,如下图所示:

        其次,一定要保证对应的业务逻辑接口不再使用@DS注解,或者新增一个无注解的接口。

总结:

        可以尝试把当前数据源缓存在Redis中,或者全局缓存中,而不是放在session会话中。自定义注解方式实现切换。自定义注解分情况,可以直接具体到方法上面。

### 多数据源拆分、切换及事务管理方法与最佳实践 #### 数据源配置与拆分策略 为了实现高效的数据管理和维护,在设计应用程序架构时应充分考虑数据源的合理分配。通过将不同业务逻辑对应的数据存储到各自独立的数据源中,能够有效降低单个数据库的压力并简化系统的整体结构[^2]。 对于具体的实施方式而言: - **基于业务模块划分**:按照应用的不同功能区域来定义相应的持久层组件和服务接口; - **读写分离机制**:针对高并发访问场景下的性能优化措施之一就是采用主从复制的方式来进行流量分流处理; ```java @Configuration public class DataSourceConfig { @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } } ``` #### 动态数据源切换技术 当面对复杂的业务需求时,可能涉及到跨越多个异构型关系型数据库的操作流程。此时就需要引入动态数据源路由方案以满足灵活调配资源的需求。借助Spring框架所提供的AOP特性,可以在不侵入现有代码的基础上完成这一目标。 具体做法是在执行SQL语句之前设置当前线程上下文中所使用的默认连接池实例名称,并在操作完成后及时清除该变量值防止内存泄漏等问题发生。 ```java @Component @Aspect @Slf4j public class DynamicDataSourceAspect { private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>(); @Around("@annotation(Dynamic)") public Object around(ProceedingJoinPoint point) throws Throwable { String dataSourceKey = ""; try { MethodSignature signature = (MethodSignature)point.getSignature(); Class<?> targetClass = point.getTarget().getClass(); Method currentMethod = targetClass.getMethod(signature.getName(), signature.getParameterTypes()); Dynamic dynamicAnnotation = currentMethod.getDeclaredAnnotation(Dynamic.class); if(dynamicAnnotation != null){ dataSourceKey = dynamicAnnotation.value(); DynamicDataSourceContextHolder.setDataSourceType(dataSourceKey); }else{ log.warn("未找到Dynamic注解"); } return point.proceed(point.getArgs()); } finally { // 清除当前线程中的数据源key, 防止内存泄露. DynamicDataSourceContextHolder.clearDataSourceType(); } } } // 自定义注解用于标记需要切换数据源的方法 @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface Dynamic { String value() default "default"; } ``` #### 事务一致性保障手段 考虑到跨库更新所带来的潜在风险因素,建议采取如下几种途径确保整个交易过程的安全可靠: - **声明式事务控制**:利用`@Transactional`标签指定特定服务函数内部的所有数据库交互都处于同一个会话周期内直至成功提交或回滚终止为止[^1]。 - **编程化API调用**:如果某些情况下不适合依赖容器自动代理,则可以通过注入`PlatformTransactionManager`对象手动开启/关闭事务边界范围。 - **分布式协调协议**:鉴于现代微服务体系日益普及的趋势下,越来越多的企业级项目开始倾向于选用诸如Seata这样的开源工具包来解决强一致性的难题[^3]。 ```xml <dependency> <groupId>io.seata</groupId> <artifactId>seata-spring-boot-starter</artifactId> <version>${latest.version}</version> </dependency> <!-- MyBatis Plus集成 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-seata</artifactId> <version>${mp_seata_version}</version> </dependency> ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

冬天豆腐

感谢支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值