欢迎大家来到IT世界,在知识的湖畔探索吧!
欢迎大家来到IT世界,在知识的湖畔探索吧!
实现数据的读写分离操作通常用于提高应用程序的性能和可伸缩性。通过将写操作(INSERT、UPDATE、DELETE)分配到主数据库,将读操作(SELECT)分配到从数据库,来减少主数据库的负载并提高系统的并发处理能力。
配置多个数据源
在Spring Boot中配置多个数据源通常包括一个主数据源用于写操作,多个从数据源用于读操作,所以要在配置文件中添加如下的配置操作。
# application.yml spring: datasource: primary: url: jdbc:mysql://primary-db:3306/mydb username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver secondary: url: jdbc:mysql://secondary-db:3306/mydb username: root password: password driver-class-name: com.mysql.cj.jdbc.Driver
欢迎大家来到IT世界,在知识的湖畔探索吧!
配置DataSource的Bean对象
根据配置的多个数据源,在SpringBoot中配置对应的DataSourceBean对象,如下所示。
欢迎大家来到IT世界,在知识的湖畔探索吧!import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.jdbc.datasource.DataSourceTransactionManager; import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource; import javax.sql.DataSource; import java.util.HashMap; import java.util.Map; @Configuration public class DataSourceConfig { @Bean(name = "primaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.primary") public DataSource primaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "secondaryDataSource") @ConfigurationProperties(prefix = "spring.datasource.secondary") public DataSource secondaryDataSource() { return DataSourceBuilder.create().build(); } @Bean(name = "dynamicDataSource") public DataSource dynamicDataSource(@Qualifier("primaryDataSource") DataSource primaryDataSource, @Qualifier("secondaryDataSource") DataSource secondaryDataSource) { AbstractRoutingDataSource routingDataSource = new AbstractRoutingDataSource() { @Override protected Object determineCurrentLookupKey() { return DynamicDataSourceContextHolder.getDataSourceKey(); } }; Map<Object, Object> dataSourceMap = new HashMap<>(); dataSourceMap.put("primary", primaryDataSource); dataSourceMap.put("secondary", secondaryDataSource); routingDataSource.setDefaultTargetDataSource(primaryDataSource); routingDataSource.setTargetDataSources(dataSourceMap); return routingDataSource; } @Bean public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DataSource dataSource) { return new DataSourceTransactionManager(dataSource); } }
实现动态数据源切换
为了实现读写分离需要在运行时切换数据源,我们可以通过ThreadLocal存储当前的数据源类型(读或写),然后在AbstractRoutingDataSource中进行切换,如下所示。
public class DynamicDataSourceContextHolder { private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>(); public static void setDataSourceKey(String key) { CONTEXT_HOLDER.set(key); } public static String getDataSourceKey() { return CONTEXT_HOLDER.get(); } public static void clearDataSourceKey() { CONTEXT_HOLDER.remove(); } }
使用AOP自动切换数据源
要想实现自动切换数据源操作,通常的做法根据方法上的注解或方法名来决定是读操作还是写操作。而我们可以通过AOP来自动切换数据源,如下所示。
欢迎大家来到IT世界,在知识的湖畔探索吧!import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @Aspect @Order(-1) // 保证在@Transactional之前执行 @Component public class DataSourceAspect { @Before("execution(* com.example.service.*.select*(..)) || execution(* com.example.service.*.get*(..))") public void setReadDataSourceType() { DynamicDataSourceContextHolder.setDataSourceKey("secondary"); } @Before("execution(* com.example.service.*.insert*(..)) || execution(* com.example.service.*.update*(..)) || execution(* com.example.service.*.delete*(..))") public void setWriteDataSourceType() { DynamicDataSourceContextHolder.setDataSourceKey("primary"); } }
确保事务管理
当使用@Transactional时,确保在切换数据源之前完成事务的设置,以保证事务的一致性和完整性。
import org.springframework.transaction.annotation.Transactional; @Service public class UserService { @Transactional public void updateUser(User user) { // 这里将使用主数据库进行写操作 userRepository.update(user); } public User getUser(Long id) { // 这里将使用从数据库进行读操作 return userRepository.findById(id); } }
总结
通过配置多个数据源、使用动态数据源切换以及通过AOP实现读写操作的自动切换,可以在Spring Boot中实现数据的读写分离。这种方式有助于提升系统的性能,特别是当读操作占比很高时。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://itzsg.com/103509.html