Spring Boot 配置 Mybatis 读写分离

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

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

需要单独增加Mybatis的配置

java 复制代码
@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 初始化时加入拦截器的配置

java 复制代码
@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 初始化时, 把数据源重新设置成有主从配置的数据源

java 复制代码
@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;
            }
        };
    }
}

再次部署测试通过

相关推荐
z晨晨17 分钟前
互联网大厂Java求职面试实战:Spring Boot与微服务场景深度解析
java·spring boot·redis·微服务·kafka·spring security·电商
码农飞哥33 分钟前
AI编程开发系统001-基于SpringBoot+Vue的旅游民宿租赁系统
vue.js·spring boot·毕业设计·ai编程·计算机源码
练习时长一年1 小时前
Bean后处理器
java·服务器·前端
野犬寒鸦1 小时前
从零起步学习Redis || 第五章:利用Redis构造分布式全局唯一ID
java·服务器·数据库·redis·分布式·后端·缓存
吹晚风吧1 小时前
SSE是什么?SSE解决什么问题?在什么场景使用SSE?
java·springboot·sse
Terio_my2 小时前
IDEA自动构建与热部署配置
java·ide·intellij-idea
数智顾问2 小时前
Java坐标转换的多元实现路径:在线调用、百度与高德地图API集成及纯Java代码实现——纯Java代码实现与数学模型深度剖析
java·开发语言
武子康2 小时前
Java-138 深入浅出 MySQL Spring Boot 事务传播机制全解析:从 REQUIRED 到 NESTED 的实战详解 传播机制原理
java·大数据·数据库·spring boot·sql·mysql·事务
码神本神3 小时前
【附源码】基于Spring Boot的高校爱心捐助平台的设计与实现
java
真的想不出名儿3 小时前
登录前验证码校验实现
java·前端·python