10分钟完成springboot集成mysql主从集群
在 Spring Boot 应用程序中集成 MySQL 主从集群涉及到配置多个数据源,确保主库(Master)用于写操作,而从库(Slave)用于读操作。首先,你需要配置 MySQL 主从复制。这通常涉及到以下步骤:在你的 Spring Boot 应用程序中,你需要配置多个数据源,一个用于主库,其他用于从库。可以使用 Spring Boot 的数据源配置和 JPA / Spring Data 来完
在 Spring Boot 应用程序中集成 MySQL 主从集群涉及到配置多个数据源,确保主库(Master)用于写操作,而从库(Slave)用于读操作。
1. MySQL 主从配置
首先,你需要配置 MySQL 主从复制。这通常涉及到以下步骤:
- 在主服务器上启用二进制日志。
- 在从服务器上配置主服务器的信息,包括服务器地址、用户凭证和要复制的数据库。
- 在从服务器上启动复制线程。
有关如何设置 MySQL 主从复制的详细信息,请参阅 MySQL 官方文档。
2. Spring Boot 配置
在你的 Spring Boot 应用程序中,你需要配置多个数据源,一个用于主库,其他用于从库。可以使用 Spring Boot 的数据源配置和 JPA / Spring Data 来完成这一任务。
2.1 Maven 依赖
确保你的 pom.xml
包含以下依赖:
<dependencies>
<!-- Spring Boot Starter Data JPA -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- MySQL Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
2.2 应用属性配置
在 application.properties
或 application.yml
文件中,配置主库和从库的数据源:
# 主库配置
spring.datasource.master.url=jdbc:mysql://master_host:port/db_name?useSSL=false
spring.datasource.master.username=db_user
spring.datasource.master.password=db_password
# 从库配置
spring.datasource.slave.url=jdbc:mysql://slave_host:port/db_name?useSSL=false
spring.datasource.slave.username=db_user
spring.datasource.slave.password=db_password
# JPA / Hibernate 配置
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=update
2.3 数据源配置类
创建一个数据源配置类来配置多个数据源:
@Configuration
public class DataSourceConfig {
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
public DynamicDataSource dataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put("master", masterDataSource);
targetDataSources.put("slave", slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
@Primary
@Bean(name = "dynamicSqlSessionFactory")
public SqlSessionFactory sqlSessionFactory(@Qualifier("dynamicDataSource") DataSource dynamicDataSource)
throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dynamicDataSource);
return sqlSessionFactoryBean.getObject();
}
@Primary
@Bean(name = "dynamicTransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
2.4 动态数据源路由
创建一个动态数据源路由类来实现 AbstractRoutingDataSource
,用于在运行时根据某些条件(如方法名或注解)选择使用主库或从库:
public class DynamicDataSource extends AbstractRoutingDataSource {
private static final ThreadLocal<String> CONTEXT_HOLDER = ThreadLocal.withInitial(() -> "master");
public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultTargetDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return CONTEXT_HOLDER.get();
}
public static void setDataSourceType(String dataSourceType) {
CONTEXT_HOLDER.set(dataSourceType);
}
public static String getDataSourceType() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSourceType() {
CONTEXT_HOLDER.remove();
}
}
2.5 AOP 切面编程
使用 AOP 来拦截特定的方法,根据方法类型(读或写)动态选择数据源:
@Aspect
@Component
public class DynamicDataSourceAspect {
@Before("@annotation(TargetDataSource)")
public void switchDataSource(JoinPoint point) {
// 获取方法上的注解
MethodSignature signature = (MethodSignature) point.getSignature();
Method method = signature.getMethod(); TargetDataSource ds = method.getAnnotation(TargetDataSource.class);
if (ds != null) {
// 根据注解值设置数据源
DynamicDataSource.setDataSourceType(ds.name(
));
} else {
// 如果没有注解,默认使用主库
DynamicDataSource.setDataSourceType("master");
}
}
@After("@annotation(TargetDataSource)") public void restoreDataSource(JoinPoint point) {
DynamicDataSource.clearDataSourceType();
}}
2.6 自定义注解
创建一个自定义注解,用于标记哪些方法应该使用主库,哪些方法应该使用从库:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface TargetDataSource {
String name() default "master";
}
3. 使用数据源
在你的服务类或 repository 中,使用自定义注解来指定方法应该使用的数据源:
@Service
public class MyService {
@Autowired
private MyRepository myRepository;
@TargetDataSource(name = "master")
public void saveData(MyEntity entity) {
myRepository.save(entity);
}
@TargetDataSource(name = "slave")
public MyEntity getDataById(Long id) {
return myRepository.findById(id).orElse(null);
}
}
4. 测试
配置完成后,你应该测试应用程序以确保主从数据源配置正确。执行一些写操作来测试主库,执行一些读操作来测试从库,并验证数据是否正确复制。
注意事项
- 确保主从服务器之间的网络连接是稳定的,并且从服务器能够正确地同步主服务器的数据。
- 考虑到数据一致性问题,如果你的应用程序需要强一致性,那么可能需要实现一些额外的逻辑来处理从库可能存在的延迟问题。
- 在生产环境中,可能需要考虑更多的因素,如负载均衡、故障转移等。
集成 MySQL 主从集群是一个复杂的过程,需要你根据应用程序的具体需求来进行适当的配置和优化。上述步骤提供了一个基本的框架,但可能需要根据实际情况进行调整。
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)