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

在现代的微服务架构中,数据库读写分离是一种常见的架构设计,通过将读操作和写操作分开,不仅可以提高系统的吞吐量,还能优化数据库的负载能力。本文将介绍如何在 Spring Boot 项目中结合 MyBatis-Plus 实现数据库的读写分离。

一、项目环境准备

  1. Spring Boot: 确保你已经搭建好了 Spring Boot 项目。
  2. MyBatis-Plus: 在 pom.xml 中加入 MyBatis-Plus 的依赖。
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.23</version>
</dependency>
  1. 数据库: 准备好一台支持读写分离的数据库实例,通常情况下可以是 MySQL。

二、配置数据源

application.yml 配置文件中配置主从数据源。我们将设置主数据库用于写操作,从数据库用于读操作。

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    hikari:
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: password
      jdbc-url: jdbc:mysql://localhost:3306/mydb?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
      maximum-pool-size: 10

# 从数据源配置
spring:
  datasource:
    read:
      type: com.zaxxer.hikari.HikariDataSource
      hikari:
        driver-class-name: com.mysql.cj.jdbc.Driver
        username: root
        password: password
        jdbc-url: jdbc:mysql://localhost:3306/mydb_slave?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
        maximum-pool-size: 10

三、创建数据源路由

我们需要创建一个数据源路由,以决定何时使用主库(用于写操作)和从库(用于读操作)。

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContext.getCurrentDataSource();
    }
}

public class DataSourceContext {
    private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();

    public static void setCurrentDataSource(String dataSource) {
        contextHolder.set(dataSource);
    }

    public static String getCurrentDataSource() {
        return contextHolder.get();
    }

    public static void clear() {
        contextHolder.remove();
    }
}

四、配置 MyBatis-Plus

在 MyBatis-Plus 配置中,我们需要设置动态数据源。

import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class MyBatisPlusConfig {
    @Bean
    public DynamicDataSource dataSource() {
        DynamicDataSource dynamicDataSource = new DynamicDataSource();
        Map<Object, Object> targetDataSources = new HashMap<>();
        targetDataSources.put("master", masterDataSource());
        targetDataSources.put("read", readDataSource());

        dynamicDataSource.setTargetDataSources(targetDataSources);
        dynamicDataSource.setDefaultTargetDataSource(masterDataSource());

        return dynamicDataSource;
    }

    @Bean
    public DataSource masterDataSource() {
        // 创建主数据源
    }

    @Bean
    public DataSource readDataSource() {
        // 创建从数据源
    }

    @Bean
    public PaginationInterceptor paginationInterceptor() {
        return new PaginationInterceptor();
    }
}

五、使用注解切换数据源

为了便于操作,我们可以创建一个自定义注解来标识读写操作。

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

接下来,我们可以实现一个 AOP 切面,根据方法的注解来切换数据源。

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class DataSourceSwitchAspect {
    @Before("@annotation(ReadOnly)")
    public void switchToRead() {
        DataSourceContext.setCurrentDataSource("read");
    }

    @Before("!@annotation(ReadOnly)")
    public void switchToWrite() {
        DataSourceContext.setCurrentDataSource("master");
    }
}

六、使用示例

接下来,我们可以在 Service 层中使用上述注解进行读写操作。

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class UserService extends ServiceImpl<UserMapper, User> {

    @ReadOnly
    public User getUserById(Long id) {
        return this.getById(id);
    }

    public void createUser(User user) {
        this.save(user);
    }
}

七、总结

通过上述步骤,我们成功实现了在 Spring Boot 项目中使用 MyBatis-Plus 的数据库读写分离。我们定义了动态数据源与 AOP 切点,能够根据操作类型轻松地切换数据库,提高了系统的可扩展性与性能。在实际项目中,读写分离是一种非常有效的解决方案,通过合理的架构设计,可以显著提升数据库的并发访问能力。

点赞(0) 打赏

微信小程序

微信扫一扫体验

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部