将 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);
}
}
在这个配置中,我们定义了两个数据源:primaryDataSource
和 secondaryDataSource
,分别连接到 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 或手动设置来决定何时使用主库或从库。