Spring Boot + MyBatis-Plus实现数据库读写分离

Alt

🎈个人主页:程序员 小侯
🎐CSDN新晋作者
🎉欢迎 👍点赞✍评论⭐收藏
✨收录专栏:Java框架
✨文章内容:Spring Boot + MyBatis-Plus
🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗

在现代应用程序的开发中,数据库读写分离是一种常见的优化手段,能够提升系统的性能和可扩展性。本文将介绍如何使用Spring Boot和MyBatis-Plus实现数据库读写分离,并提供详细的代码示例。
在这里插入图片描述

1. 引入依赖

首先,在pom.xml文件中添加Spring Boot和MyBatis-Plus的依赖:

<dependencies>
    <!-- Spring Boot Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>

    <!-- MyBatis-Plus Starter -->
    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.4.2</version>
    </dependency>

    <!-- 数据库驱动,以MySQL为例 -->
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.23</version>
    </dependency>
</dependencies>

2. 配置数据源

application.propertiesapplication.yml中配置主从数据源:

# 主数据源配置
spring.datasource.master.url=jdbc:mysql://master-host:3306/master_db
spring.datasource.master.username=master_user
spring.datasource.master.password=master_password
spring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver

# 从数据源配置
spring.datasource.slave.url=jdbc:mysql://slave-host:3306/slave_db
spring.datasource.slave.username=slave_user
spring.datasource.slave.password=slave_password
spring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver

3. 配置MyBatis-Plus

创建MyBatisPlusConfig类,配置MyBatis-Plus的分页插件和多数据源:

@Configuration
@MapperScan("com.example.mapper")
public class MyBatisPlusConfig {

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

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

    @Bean
    public MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(
            @Qualifier("masterDataSource") DataSource masterDataSource,
            @Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception {
        MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();
        sessionFactoryBean.setDataSource(masterDataSource);
        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver()
                .getResources("classpath:mapper/*.xml"));

        MybatisConfiguration configuration = new MybatisConfiguration();
        configuration.setMapUnderscoreToCamelCase(true);
        configuration.setCacheEnabled(false);

        Interceptor[] interceptors = new Interceptor[]{
                new PaginationInterceptor(),
                new DynamicDataSourceInterceptor()
        };
        configuration.setInterceptors(interceptors);

        sessionFactoryBean.setConfiguration(configuration);

        return sessionFactoryBean;
    }

    @Bean
    public PlatformTransactionManager platformTransactionManager(
            @Qualifier("masterDataSource") DataSource masterDataSource,
            @Qualifier("slaveDataSource") DataSource slaveDataSource) {
        return new DataSourceTransactionManager(masterDataSource, slaveDataSource);
    }
}

在上述配置中,我们使用了DynamicDataSourceInterceptor拦截器,它实现了MyBatis的Interceptor接口,用于动态切换数据源。

4. 实现动态数据源

创建DynamicDataSource类,用于动态获取当前线程的数据源:

public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        return DynamicDataSourceContextHolder.getDataSourceKey();
    }
}

创建DynamicDataSourceContextHolder类,用于设置和获取当前线程的数据源:

public class DynamicDataSourceContextHolder {

    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDataSourceKey(String dataSourceKey) {
        CONTEXT_HOLDER.set(dataSourceKey);
    }

    public static String getDataSourceKey() {
        return CONTEXT_HOLDER.get();
    }

    public static void clearDataSourceKey() {
        CONTEXT_HOLDER.remove();
    }
}

5. 实现动态数据源拦截器

创建DynamicDataSourceInterceptor拦截器,用于在执行SQL前动态切换数据源:

public class DynamicDataSourceInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        boolean clearFlag = false;
        Signature signature = invocation.getSignature();
        if (signature instanceof MethodSignature) {
            MethodSignature methodSignature = (MethodSignature) signature;
            if (methodSignature.getMethod().isAnnotationPresent(ReadOnly.class)) {
                DynamicDataSourceContextHolder.setDataSourceKey("slaveDataSource");
                clearFlag = true;
            }
        }

        try {
            return invocation.proceed();
        } finally {
            if (clearFlag) {
                DynamicDataSourceContextHolder.clearDataSourceKey();
            }
        }
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 暂时不需要配置
    }
}

在上述代码中,我们通过@ReadOnly注解标记只读操作,从而触发数据源切换。

6. 实现自定义注解

创建ReadOnly注解,用于标记只读操作:

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReadOnly {
}

7. 使用注解标记只读操作

在Service层的方法上使用@ReadOnly注解标记只读操作:

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

    @ReadOnly
    public List<User> getAllUsers() {
        return userMapper.selectList(null);
    }

    // 其他方法
}

通过以上步骤,我们成功地实现了Spring Boot与MyBatis-Plus的数据库读写分离。在只读操作上使用@ReadOnly注解,拦截器会动态切换到从数据源,从而提升了系统的查询性能。

这种方式的优点在于配置简单,只需要在只读操作上添加注解即可。同时,该方案也具备一定的灵活性,可以根据实际情况进行调整和

扩展。在高并发的系统中,数据库读写分离是提升性能的有效手段之一,通过本文的介绍,相信读者能够在实际项目中成功应用这一技术。

后记 👉👉💕💕美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!! 🌹🌹🌹

  • 23
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

程序员 小侯

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值