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

Spring Boot 配置 Mybatis 读写分离

JPA 的读写分离配置不能应用在 Mybatis 上, 所以 Mybatis 要单独处理

为了不影响原有代码, 使用了增加拦截器的方式, 在拦截器里根据 SQL 的 CRUD 来路由到不同的数据源

需要单独增加Mybatis的配置

@Configuration
public class MyBatisConfig {
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
        sessionFactory.setDataSource(dataSource);

        // 注册插件
        sessionFactory.setPlugins(new Interceptor[]{new DataSourceInterceptor()});

        return sessionFactory.getObject();
    }
}

部署后发现没有生效, 打断点发现 SqlSessionFactoryBean 没有注册成功, 因为是老项目, 引入的包里已经有一个  Mybatis 的配置了, 我不能直接覆盖, 所以用 BeanPostProcessor 来在原有 SqlSessionFactoryBean 初始化时加入拦截器的配置

@Configuration
public class MyBatisConfig {
    @Bean
    @ConditionalOnBean(name="routingDataSource")
    public BeanPostProcessor sqlSessionFactoryBeanPostProcessor(@Qualifier("routingDataSource") DataSource routingDataSource) {
        return new BeanPostProcessor() {
            @Override
            public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof SqlSessionFactory) {
                    SqlSessionFactory SqlSessionFactory = (SqlSessionFactory) bean;
                    try {
                        SqlSessionFactory.getConfiguration().addInterceptor(new DataSourceInterceptor());
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                }
                return bean;
            }
        };
    }
}

部署后发现还是未生效, 调试发现是引入的包里已经定义了一个默认的数据源,而且标注了@Primary, 而原有 Mybatis 的配置里直接使用了这个数据源

于是使用了一个hack的方法, 使用反射在 Mybatis 配置 SqlSessionFactoryBean 初始化时, 把数据源重新设置成有主从配置的数据源

@Configuration
public class MyBatisConfig {
    @Bean
    @ConditionalOnBean(name="routingDataSource")
    public BeanPostProcessor sqlSessionFactoryBeanPostProcessor(@Qualifier("routingDataSource") DataSource routingDataSource) {
        return new BeanPostProcessor() {
@Override
            public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
                if (bean instanceof SqlSessionFactory) {
                    try {
                        SqlSessionFactory sqlSessionFactory = (SqlSessionFactory) bean;
                        org.apache.ibatis.session.Configuration configuration = sqlSessionFactory.getConfiguration();

                        // 使用反射或其他方式修改配置中的数据源
                        Field dataSourceField = configuration.getEnvironment().getClass().getDeclaredField("dataSource");
                        dataSourceField.setAccessible(true);
                        dataSourceField.set(configuration.getEnvironment(), routingDataSource);
                    } catch (Exception e) {
                        throw new BeansException("Failed to modify SqlSessionFactory", e) {};
                    }

                }
                return bean;
            }
        };
    }
}

再次部署测试通过

相关文章:

  • mapbox进阶,添加绘图扩展插件,绘制任意方向矩形
  • 【LLM】13:大模型算法面试题库
  • Python客户端和C服务器之间的连接问题及其解决方案
  • 在 Windows 系统中如何快速进入安全模式的两种方法
  • Django中select_related 的作用
  • 51单片机看门狗系统
  • 读取本地excel删除第一行,并生成List数组
  • 贪心算法与动态规划的区别
  • GPT-4o微调SFT及强化学习DPO数据集构建
  • 装饰器模式 + 责任链模式:动态增强的流水线处理艺术
  • Modbus TCP协议
  • 【第2章:神经网络基础与实现——2.1 前馈神经网络的结构与工作原理】
  • 亚远景-ASPICE 4.0 与 AI 驱动的汽车软件开发:未来趋势与挑战
  • 力扣第一题 哈希解法 O(n)时间复杂度
  • zyNo.23
  • springcloud集成gateway
  • 将Sqlite3数据库挂在内存上处理
  • 【STM32系列】利用MATLAB配合ARM-DSP库设计IIR数字滤波器(保姆级教程)
  • GPU并行计算的深度学习pyTorch环境搭建
  • WinForm 防破解、反编译设计文档
  • 在古老的意大利科莫歌剧院,廖昌永唱响16首中国艺术歌曲
  • 安徽省委常委、合肥市委书记费高云卸任副省长职务
  • 多地警务新媒体整合:关停交警等系统账号,统一信息发布渠道
  • 讲一个香港儿童的故事,《劏房的天空》获“周庄杯”特等奖
  • 山东枣庄同一站点两名饿了么骑手先后猝死,当地热线:职能部门正调查
  • 被流量绑架人生,《人生开门红》能戳破网络时代的幻象吗