数据量猛增,通过动态数据源切换,我们不仅能提高查询效率,还能保证系统的高可用性。
通过将写操作集中在主库,读操作分散到多个从库,可以有效减轻数据库的压力。
在pom.xml中添加以下依赖:
xml
<dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jdbc</artifactId>
 </dependency>
 <dependency>
 <groupId>com.baomidou</groupId>
 <artifactId>mybatis-plus-boot-starter</artifactId>
 <version>3.4.3</version>
 </dependency>
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-aop</artifactId>
 </dependency>
application.yml中的数据源配置
yaml
spring:
 datasource:
 primary:
 url: jdbc:mysql://localhost:3306/primary_db
 username: root
 password: root
 driver-class-name: com.mysql.cj.jdbc.Driver
 replica:
 url: jdbc:mysql://localhost:3306/replica_db
 username: root
 password: root
 driver-class-name: com.mysql.cj.jdbc.Driver
在这里,我们配置了两个数据源,
一个主库primary
一个从库replica。
这样我们就可以在业务中区分读写操作了。
枚举类型与数据源上下文
为了实现动态数据源切换,我们需要定义数据源的类型,并通过上下文管理当前数据源。
DatabaseType枚举的设计
 
 
 
java
public enum DatabaseType {
 PRIMARY, // 主库
 REPLICA // 从库
 }
DataSourceContextHolder的实现与作用
 
 
 
java
public class DataSourceContextHolder {
 // 使用ThreadLocal存储当前线程的数据源类型
 private static final ThreadLocal<DatabaseType> contextHolder = new ThreadLocal<>();
 // 设置数据源类型
 public static void setDatabaseType(DatabaseType type) {
 contextHolder.set(type);
 }
 // 获取数据源类型
 public static DatabaseType getDatabaseType() {
 return contextHolder.get();
 }
 // 清除数据源类型
 public static void clearDatabaseType() {
 contextHolder.remove();
 }
 }
通过上述代码,我们可以在不同的线程中安全地设置和获取当前数据源的类型。
动态数据源的实现机制
动态数据源的核心是继承并重写AbstractRoutingDataSource类。
DynamicDataSource类的继承与重写
 
 
 
java
public class DynamicDataSource extends AbstractRoutingDataSource {
 @Override
 protected Object determineCurrentLookupKey() {
 // 从上下文中获取当前数据源的类型
 return DataSourceContextHolder.getDatabaseType();
 }
 }
通过继承
AbstractRoutingDataSource,我们可以在运行时根据上下文动态切换数据源
为了方便使用,我们可以设计一个自定义注解@DataSource来标识需要切换数据源的方法或类。
@DataSource注解的定义
 
 
 
java
@Target({ElementType.METHOD, ElementType.TYPE})
 @Retention(RetentionPolicy.RUNTIME)
 @Documented
 public @interface DataSource {
 DatabaseType value() default DatabaseType.PRIMARY; // 默认使用主库
 }
注解在类和方法上的使用示例

使用自定义注解,我们可以方便地在方法上切换数据源。
数据源切换的AOP实现
通过AOP,我们可以在方法执行前后切换数据源。
DataSourceAspect切面类的编写
 
 
 
java
@Aspect
 @Component
 public class DataSourceAspect {
 @Around("@annotation(dataSource)")
 public Object switchDataSource(ProceedingJoinPoint point, DataSource dataSource) throws Throwable {
 try {
 // 在方法执行前设置数据源
 DataSourceContextHolder.setDatabaseType(dataSource.value());
 return point.proceed(); // 执行目标方法
 } finally {
 // 在方法执行后清除数据源
 DataSourceContextHolder.clearDatabaseType();
 }
 }
 }
通过环绕通知,我们可以在方法执行前后设置和清除数据源,确保数据源切换的正确性。
配置类负责创建和管理多个数据源,并将它们注册到Spring容器中。
DataSourceConfig的职责与实现
 
 
 
java
@Configuration
 public class DataSourceConfig {
 @Bean
 @Primary
 @ConfigurationProperties(prefix = "spring.datasource.primary")
 public DataSource primaryDataSource() {
 return DataSourceBuilder.create().build(); // 创建主数据源
 }
 @Bean
 @ConfigurationProperties(prefix = "spring.datasource.replica")
 public DataSource replicaDataSource() {
 return DataSourceBuilder.create().build(); // 创建从数据源
 }
 @Bean
 public DataSource dataSource() {
 Map<Object, Object> targetDataSources = new HashMap<>();
 targetDataSources.put(DatabaseType.PRIMARY, primaryDataSource());
 targetDataSources.put(DatabaseType.REPLICA, replicaDataSource());
 DynamicDataSource dataSource = new DynamicDataSource();
 dataSource.setDefaultTargetDataSource(primaryDataSource()); // 设置默认数据源
 dataSource.setTargetDataSources(targetDataSources); // 设置目标数据源
 return dataSource;
 }
 }
通过这个配置类,我们可以将多个数据源注册到Spring容器中,并设置默认数据源和目标数据源。
为了在MyBatis-Plus中使用动态数据源,我们需要配置SqlSessionFactory和SqlSessionTemplate。
DynamicDataSourceConfig的配置
 
 
 
java
@Configuration
 @MapperScan("com.example.mapper")
 public class DynamicDataSourceConfig {
 @Autowired
 private DataSource dataSource;
 @Bean
 public SqlSessionFactory sqlSessionFactory() throws Exception {
 SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
 factoryBean.setDataSource(dataSource);
 return factoryBean.getObject();
 }
 @Bean
 public SqlSessionTemplate sqlSessionTemplate() throws Exception {
 return new SqlSessionTemplate(sqlSessionFactory());
 }
 }
通过配置
SqlSessionFactory和SqlSessionTemplate,我们可以确保MyBatis-Plus能够使用动态数据源。
主从数据库同步策略
实时同步方案的推荐


最后说一句(求关注!别白嫖!)
如果这篇文章对您有所帮助,或者有所启发的话,求一键三连:点赞、转发、在看。
关注公众号:woniuxgg,在公众号中回复:笔记 就可以获得蜗牛为你精心准备的java实战语雀笔记,回复面试、开发手册、有超赞的粉丝福利!



















