在分布式架构中,Spring Boot 可以通过多种方式实现读写分离,以提升系统性能和扩展性。以下是常见的实现方法:
1. 使用多数据源
通过配置多个数据源,将读操作和写操作分别路由到不同的数据库实例。
实现步骤:
-
配置多数据源:
在application.yml
或application.properties
中配置主从数据源。spring:datasource:master:url: jdbc:mysql://master-host:3306/dbusername: rootpassword: rootslave:url: jdbc:mysql://slave-host:3306/dbusername: rootpassword: root
-
创建数据源配置类:
使用@Configuration
和@Bean
注解配置主从数据源。@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();}@Primary@Bean(name = "routingDataSource")public DataSource routingDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put("master", masterDataSource);targetDataSources.put("slave", slaveDataSource);AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() {@Overrideprotected Object determineCurrentLookupKey() {return DataSourceContextHolder.getDataSourceKey();}};routingDataSource.setDefaultTargetDataSource(masterDataSource);routingDataSource.setTargetDataSources(targetDataSources);return routingDataSource;} }
-
数据源上下文管理:
使用ThreadLocal
管理当前线程的数据源。public class DataSourceContextHolder {private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();public static void setDataSourceKey(String key) {contextHolder.set(key);}public static String getDataSourceKey() {return contextHolder.get();}public static void clearDataSourceKey() {contextHolder.remove();} }
-
AOP 切面实现数据源切换:
通过 AOP 在方法执行前切换数据源。@Aspect @Component public class DataSourceAspect {@Before("@annotation(com.example.annotation.Master)")public void setMasterDataSource() {DataSourceContextHolder.setDataSourceKey("master");}@Before("@annotation(com.example.annotation.Slave)")public void setSlaveDataSource() {DataSourceContextHolder.setDataSourceKey("slave");}@After("@annotation(com.example.annotation.Master) || @annotation(com.example.annotation.Slave)")public void clearDataSource() {DataSourceContextHolder.clearDataSourceKey();} }
-
自定义注解:
定义@Master
和@Slave
注解,用于标记方法使用主库或从库。@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Master { }@Target({ElementType.METHOD, ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Slave { }
-
在 Service 层使用注解:
在 Service 层方法上使用@Master
或@Slave
注解。@Service public class UserService {@Autowiredprivate UserMapper userMapper;@Masterpublic void addUser(User user) {userMapper.insert(user);}@Slavepublic User getUserById(Long id) {return userMapper.selectById(id);} }
2. 使用中间件
借助数据库中间件(如 MyCAT、ShardingSphere)自动实现读写分离,减少应用层代码的复杂性。
实现步骤:
-
配置中间件:
在中间件中配置主从数据库,并设置读写分离规则。 -
应用连接中间件:
在 Spring Boot 中配置数据源连接中间件,而非直接连接数据库。
3. 使用 Spring Cloud 组件
在微服务架构中,结合 Spring Cloud 组件(如 Spring Cloud Gateway、Spring Cloud Config)动态管理数据源。
实现步骤:
-
配置中心管理数据源:
使用 Spring Cloud Config 动态更新数据源配置。 -
服务网关路由:
通过 Spring Cloud Gateway 实现请求路由,将读写请求分发到不同服务实例。
总结
Spring Boot 实现读写分离的常见方法包括多数据源配置、中间件和 Spring Cloud 组件。多数据源配置适合中小型项目,中间件适合大型分布式系统,Spring Cloud 组件则适合微服务架构。选择合适的方法取决于具体需求和系统规模。