当前位置: 首页 > news >正文

Java高频面试题:MyBatis如何实现动态数据源切换?

大家好,我是锋哥。今天分享关于【Java高频面试题:MyBatis如何实现动态数据源切换?】面试题 。希望对大家有帮助;

Java高频面试题:MyBatis如何实现动态数据源切换?

1️⃣ 基本思路

在 MyBatis(或 Spring + MyBatis)中,动态切换数据源的核心思想是:

  1. 定义多个数据源(DataSource)。
  2. 使用一个动态数据源路由器(DynamicDataSource),在运行时根据上下文决定使用哪个数据源。
  3. 在方法或线程执行前,设置当前线程使用的数据源标识(通常用ThreadLocal保存)。
  4. MyBatis 的SqlSession或 SpringJdbcTemplate会通过动态数据源路由器获取当前的数据源。

关键点:线程安全。每个线程单独维护自己的数据源标识,防止并发下数据源错乱。


2️⃣ 核心实现步骤

2.1 定义数据源

通常在application.ymlapplication.properties中配置多个数据源,例如:

spring: datasource: master: url: jdbc:mysql://localhost:3306/master username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver slave: url: jdbc:mysql://localhost:3306/slave username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver

在 Spring 中配置对应的DataSourceBean:

@Bean @Primary @ConfigurationProperties(prefix = "spring.datasource.master") public DataSource masterDataSource() { return DataSourceBuilder.create().build(); } @Bean @ConfigurationProperties(prefix = "spring.datasource.slave") public DataSource slaveDataSource() { return DataSourceBuilder.create().build(); }

2.2 创建动态数据源

public class DynamicDataSource extends AbstractRoutingDataSource { // 核心方法,根据当前线程的数据源标识返回对应 DataSource @Override protected Object determineCurrentLookupKey() { return DataSourceContextHolder.getDataSource(); } }

DataSourceContextHolder用于管理线程数据源:

public class DataSourceContextHolder { private static final ThreadLocal<String> CONTEXT = new ThreadLocal<>(); public static void setDataSource(String dataSource) { CONTEXT.set(dataSource); } public static String getDataSource() { return CONTEXT.get(); } public static void clear() { CONTEXT.remove(); } }

然后在配置类里:

@Bean public DataSource dynamicDataSource(DataSource masterDataSource, DataSource slaveDataSource) { Map<Object, Object> targetDataSources = new HashMap<>(); targetDataSources.put("master", masterDataSource); targetDataSources.put("slave", slaveDataSource); DynamicDataSource dynamicDataSource = new DynamicDataSource(); dynamicDataSource.setDefaultTargetDataSource(masterDataSource); // 默认数据源 dynamicDataSource.setTargetDataSources(targetDataSources); return dynamicDataSource; }

2.3 MyBatis 配置动态数据源

在 Spring Boot 中,通常直接配置 MyBatis 使用动态数据源:

@Bean public SqlSessionFactory sqlSessionFactory(DataSource dynamicDataSource) throws Exception { SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); sessionFactory.setDataSource(dynamicDataSource); return sessionFactory.getObject(); }

2.4 在代码中切换数据源

可以在服务方法上通过AOP 或注解来切换数据源,例如:

@Target({ ElementType.METHOD, ElementType.TYPE }) @Retention(RetentionPolicy.RUNTIME) public @interface DataSource { String value() default "master"; }

AOP 切面实现:

@Aspect @Component public class DataSourceAspect { @Before("@annotation(dataSource)") public void switchDataSource(DataSource dataSource) { DataSourceContextHolder.setDataSource(dataSource.value()); } @After("@annotation(dataSource)") public void clearDataSource(DataSource dataSource) { DataSourceContextHolder.clear(); } }

然后在 Service 方法上标注:

@Service public class UserService { @DataSource("slave") public List<User> getUsersFromSlave() { return userMapper.selectAll(); } @DataSource("master") public void insertUser(User user) { userMapper.insert(user); } }

✅ 这样就实现了按方法动态切换数据源


3️⃣ 注意事项

  1. 事务管理
    动态数据源切换必须配合 Spring 的事务管理,否则可能出现事务跨数据源异常。

    • 通常使用@Transactional注解配合AbstractRoutingDataSource即可。
  2. 线程安全
    必须使用ThreadLocal来保证每个线程独立使用数据源标识,否则并发请求可能混乱。

  3. 性能考虑
    切换数据源比单一数据源略有开销,尤其是在高并发下,需要注意连接池的配置。


💡 总结:
MyBatis 的动态数据源切换本质是AbstractRoutingDataSource + ThreadLocal的组合,通过 AOP 或手动设置当前线程的数据源来实现方法级的数据源切换。

http://www.jsqmd.com/news/604414/

相关文章:

  • Ostrakon-VL自动化测试报告生成:扫描UI并对比需求文档
  • 铸造车间混砂机的传动装置设计【solidworks三维+cad图纸+毕业论文】
  • Windows下玩转Llama.cpp量化:从HF模型到GGUF格式的保姆级转换教程
  • 解放双手!这些PPT生成网站,轻松开启高效创作 - 品牌测评鉴赏家
  • 医美抖音AI客服推荐,低成本撬动本地医美获客增长
  • NFT系统开发:在数字荒原上播种「文明契约」
  • 开箱即用!Qwen3-VL-8B AI聊天系统一键启动,小白也能玩转
  • 嵌入式开发实战:如何用STM32实现串口控制LED灯(附完整代码)
  • Tsuru平台安全加固终极指南:10个关键步骤保护你的PaaS环境
  • 牙科(口腔科)小红书AI客服推荐,高净值流量精准转化
  • 莫比乌斯反演 学习笔记
  • LS-DYNA R11与R13安装包|专注爆炸冲击与瞬态动力学仿真
  • 如何使用HVM2实现高效并行数据处理:从基础到实战指南
  • AI博主实测|3款封神PPT工具,新手也能10分钟出质感大片 - 品牌测评鉴赏家
  • 永生代码刑责:数字灵魂崩溃致死案开庭
  • React on Rails 国际化(i18n)终极指南:如何快速实现多语言支持
  • 杀死Scrum Master:智能体接管敏捷全流程的灾难
  • 终极指南:如何用Instructor实现舞蹈动作的结构化解析与智能编舞建议
  • 易语言自动寻路算法源代码下载|脚本开发参考范例
  • 基于FPGA的信号处理算法,FFT法相差检测verilog实现 1.硬件平台:altera芯片...
  • STM32H7实战:用CubeMX动态切换主频(72M到16M)的保姆级避坑指南
  • nnUNet实战调优笔记:batch_size与patch_size参数调整策略详解
  • 前端开发连续面了一周,我现在强的可怕!
  • 7个终极技巧:用nbdev实现完美的测试覆盖率分析
  • 计算机考研408真题实战:CRC校验与模2除法的C语言实现
  • AI Agent进阶必学:Harness是什么?与Framework的核心区别+实战拆解
  • 联想y9000p电脑,开机经常出现“请稍等”界面,时间长达半小时——到底什么原因——和系统没有完全更新好有关-完全更新后,再暂停更新试试。-win11家庭中文版
  • 如何用PocketBase打造高性能游戏后端:玩家数据管理与实时对战系统全指南
  • 如何在 SEO 编辑岗位上实现晋升
  • esp32-c3驱动MAX6955AAX并驱动1088AS点阵屏