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

文章目录

    • [1. 引入依赖](#1. 引入依赖)
    • [2. 配置数据源](#2. 配置数据源)
    • [3. 配置MyBatis-Plus](#3. 配置MyBatis-Plus)
    • [4. 实现动态数据源](#4. 实现动态数据源)
    • [5. 实现动态数据源拦截器](#5. 实现动态数据源拦截器)
    • [6. 实现自定义注解](#6. 实现自定义注解)
    • [7. 使用注解标记只读操作](#7. 使用注解标记只读操作)

🎈个人主页:程序员 小侯

🎐CSDN新晋作者

🎉欢迎 👍点赞✍评论⭐收藏

✨收录专栏:Java框架

✨文章内容:Spring Boot + MyBatis-Plus

🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗

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

1. 引入依赖

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

xml 复制代码
<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中配置主从数据源:

properties 复制代码
# 主数据源配置
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的分页插件和多数据源:

java 复制代码
@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类,用于动态获取当前线程的数据源:

java 复制代码
public class DynamicDataSource extends AbstractRoutingDataSource {

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

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

java 复制代码
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前动态切换数据源:

java 复制代码
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注解,用于标记只读操作:

java 复制代码
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ReadOnly {
}

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

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

java 复制代码
@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

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

    // 其他方法
}

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

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

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

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

相关推荐
NiNg_1_2341 小时前
SpringBoot整合SpringSecurity实现密码加密解密、登录认证退出功能
java·spring boot·后端
种树人202408191 小时前
如何在 Spring Boot 中启用定时任务
spring boot
Ai 编码助手4 小时前
MySQL中distinct与group by之间的性能进行比较
数据库·mysql
陈燚_重生之又为程序员4 小时前
基于梧桐数据库的实时数据分析解决方案
数据库·数据挖掘·数据分析
caridle4 小时前
教程:使用 InterBase Express 访问数据库(五):TIBTransaction
java·数据库·express
白云如幻4 小时前
MySQL排序查询
数据库·mysql
萧鼎4 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
^velpro^4 小时前
数据库连接池的创建
java·开发语言·数据库
苹果醋34 小时前
Java8->Java19的初步探索
java·运维·spring boot·mysql·nginx
荒川之神4 小时前
ORACLE _11G_R2_ASM 常用命令
数据库·oracle