Spring Boot3 配合ProxySQL实现对 MySQL 主从同步的读写分离和负载均衡

ProxySQL 配合 Spring Boot 使用,主要的目的是在 Spring Boot 应用程序中实现对 MySQL 主从同步的读写分离和负载均衡。这样,你可以利用 ProxySQL 自动将写操作路由到主库,而将读操作路由到从库。

1. 准备工作

确保你的 MySQL 主从同步环境和 ProxySQL 已经成功配置并正常工作。接下来,我们将进行以下几个步骤:

  • 配置 Spring Boot 连接 ProxySQL。
  • 配置 数据源 来支持读写分离。

2. 修改 Spring Boot 配置

在 Spring Boot 项目中,配置数据库连接时,使用 ProxySQL 作为 MySQL 的代理。你需要将 Spring Boot 的 数据源配置 进行一些调整,以支持读写分离。

1.1 配置 application.yml(或 application.properties

你可以在 application.yml 中配置多个数据源,分别对应主库和从库。ProxySQL 会作为一个代理处理读写分离。

示例:application.yml
yaml 复制代码
spring:
  datasource:
    # 主数据源 (写库)
    primary:
      url: jdbc:mysql://127.0.0.1:6033/mydb
      username: your_user
      password: your_password
      driver-class-name: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 10
        minimum-idle: 5
        pool-name: PrimaryPool
    # 从数据源 (读库)
    secondary:
      url: jdbc:mysql://127.0.0.1:6033/mydb
      username: your_user
      password: your_password
      driver-class-name: com.mysql.cj.jdbc.Driver
      hikari:
        maximum-pool-size: 10
        minimum-idle: 5
        pool-name: SecondaryPool

  # 设置数据源的路由策略
  jpa:
    hibernate:
      ddl-auto: update
    properties:
      hibernate:
        dialect: org.hibernate.dialect.MySQL8Dialect
    show-sql: true
    database-platform: org.hibernate.dialect.MySQL8Dialect

在这个配置文件中:

  • 主数据源(primary)用于写入操作,连接到 ProxySQL 的主库。
  • 从数据源(secondary)用于读取操作,连接到 ProxySQL 的从库。

ProxySQL 会根据 SQL 语句的类型(SELECT 路由到从库,INSERT/UPDATE 路由到主库)自动分配流量。

1.2 配置 DataSource 路由

Spring Boot 默认只支持单个数据源。如果你需要同时配置多个数据源(主从分离),需要定义一个 数据源路由 类,将请求的数据库连接动态路由到主库或从库。

java 复制代码
@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = "com.example.repository")
public class DataSourceConfig {

    @Primary
    @Bean(name = "primaryDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.primary")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

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

    // 配置EntityManagerFactory和TransactionManager
    @Bean(name = "entityManagerFactory")
    public LocalContainerEntityManagerFactoryBean entityManagerFactory(
            EntityManagerFactoryBuilder builder, 
            @Qualifier("primaryDataSource") DataSource dataSource) {
        return builder
                .dataSource(dataSource)
                .packages("com.example.model") // 你的实体类包路径
                .persistenceUnit("primary")
                .build();
    }

    @Bean(name = "transactionManager")
    public PlatformTransactionManager transactionManager(
            @Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory) {
        return new JpaTransactionManager(entityManagerFactory);
    }
}

在这个配置中,我们定义了两个数据源:primaryDataSourcesecondaryDataSource,分别连接到 ProxySQL 的主库和从库。

3. 实现动态数据源路由

为了动态选择使用主库还是从库,你可以使用一个 AbstractRoutingDataSource 来实现动态的数据源路由。

java 复制代码
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Override
    protected Object determineCurrentLookupKey() {
        // 判断当前线程中是否有读请求或者写请求,选择数据源
        return DataSourceContextHolder.getDataSourceType();
    }
}

然后创建一个 DataSourceContextHolder 用来管理当前线程的数据源类型。

java 复制代码
public class DataSourceContextHolder {

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

    public static void setDataSourceType(String dataSourceType) {
        contextHolder.set(dataSourceType);
    }

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

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

4. 配置 Service 层的读写分离

接下来,你需要在服务层中手动切换读写操作的数据源。通常,你可以通过注解来区分读操作和写操作。

java 复制代码
@Service
public class UserService {

    @Transactional
    public void saveUser(User user) {
        // 使用主库保存数据
        DataSourceContextHolder.setDataSourceType("primary");
        userRepository.save(user);
        DataSourceContextHolder.clearDataSourceType();
    }

    public User getUser(Long id) {
        // 使用从库查询数据
        DataSourceContextHolder.setDataSourceType("secondary");
        User user = userRepository.findById(id).orElse(null);
        DataSourceContextHolder.clearDataSourceType();
        return user;
    }
}

在上面的代码中,saveUser 方法会选择主库,而 getUser 方法会选择从库。

5. 配置 Spring AOP 自动切换数据源(可选)

你可以通过 AOP 来简化读写分离的配置,使得你不需要手动设置数据源类型。只需在方法上使用自定义注解(如 @ReadOnly@WriteOnly),自动切换数据源。

自定义注解:
java 复制代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ReadOnly {
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WriteOnly {
}
创建 AOP 切面:
java 复制代码
@Aspect
@Component
public class DataSourceAspect {

    @Before("@annotation(ReadOnly)")
    public void setReadOnlyDataSource() {
        DataSourceContextHolder.setDataSourceType("secondary");
    }

    @Before("@annotation(WriteOnly)")
    public void setWriteOnlyDataSource() {
        DataSourceContextHolder.setDataSourceType("primary");
    }

    @After("@annotation(ReadOnly) || @annotation(WriteOnly)")
    public void clearDataSource() {
        DataSourceContextHolder.clearDataSourceType();
    }
}

在这段代码中:

  • 使用 @ReadOnly 注解的方法将会切换到从库。
  • 使用 @WriteOnly 注解的方法将会切换到主库。

6. 总结

通过以上步骤,你可以将 ProxySQL 与 Spring Boot 集成,实现 MySQL 主从同步的读写分离和负载均衡。

  • ProxySQL 作为 MySQL 的代理,负责将读请求路由到从库,写请求路由到主库。
  • Spring Boot 通过配置多个数据源和动态路由来实现读写分离。
  • 你可以通过 AOP 或手动设置来决定何时使用主库或从库。
相关推荐
等一场春雨24 分钟前
MySQL 主从同步中间件
数据库·mysql·中间件
鹿屿二向箔28 分钟前
一个基于Spring Boot的简单网吧管理系统
spring boot·后端·python
ICT技术最前线1 小时前
“负载均衡”出站的功能、原理与场景案例
网络·负载均衡
计算机-秋大田1 小时前
基于Spring Boot的扶贫助农系统设计与实现(LW+页码+讲解)
java·vue.js·spring boot·后端·课程设计
悟纤2 小时前
Docker入门篇[SpringBoot之Docker实战系列] - 第534篇
spring boot·docker·eureka
白露与泡影2 小时前
Spring Boot性能提升的核武器,速度提升500%!
java·spring boot·后端
昔我往昔2 小时前
Spring Boot中的依赖注入是如何工作
java·spring boot·后端
豪宇刘3 小时前
Redis 安装与 Spring Boot 集成指南
spring boot·redis·缓存
一决威严-雪雪3 小时前
springboot整合拦截器
java·spring boot·后端