在分布式架构中,Spring Boot 可以通过多种方式实现读写分离,以提升系统性能和扩展性。以下是常见的实现方法:
1. 使用多数据源
通过配置多个数据源,将读操作和写操作分别路由到不同的数据库实例。
实现步骤:
-
配置多数据源:
在application.yml
或application.properties
中配置主从数据源。spring: datasource: master: url: jdbc:mysql://master-host:3306/db username: root password: root slave: url: jdbc:mysql://slave-host:3306/db username: root password: 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() { @Override protected 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 { @Autowired private UserMapper userMapper; @Master public void addUser(User user) { userMapper.insert(user); } @Slave public 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 组件则适合微服务架构。选择合适的方法取决于具体需求和系统规模。