spring boot 多数据源_Spring Boot2(四):使用Spring Boot多数据源实现读写分离
时间: 2023-06-24 18:03:18 浏览: 155
在Spring Boot应用中使用多数据源可以实现读写分离,提高系统的性能和可用性,同时也可以满足不同业务场景下的需求。下面我们来介绍如何使用Spring Boot多数据源实现读写分离。
1. 添加依赖
在pom.xml文件中添加以下依赖:
```
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
```
其中,spring-boot-starter-jdbc是Spring Boot提供的JDBC Starter,用于连接数据库。druid是阿里巴巴开源的数据库连接池。
2. 配置数据源
在application.yml文件中添加数据源配置:
```
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/test1?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/test2?useUnicode=true&characterEncoding=utf-8&useSSL=false
username: root
password: 123456
driver-class-name: com.mysql.jdbc.Driver
```
其中,我们配置了两个数据源:master和slave。分别连接了两个不同的数据库,用于实现读写分离。
3. 配置数据源和事务管理器
在Spring Boot中,我们需要自己配置数据源和事务管理器。可以在代码中通过@Primary和@Qualifier注解实现数据源的动态切换。
```
@Configuration
public class DataSourceConfig {
@Bean(name = "masterDataSource")
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "slaveDataSource")
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
@Primary
public DynamicDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DynamicDataSource.DataSourceType.MASTER, masterDataSource);
targetDataSources.put(DynamicDataSource.DataSourceType.SLAVE, slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
@Bean(name = "transactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("dynamicDataSource") DynamicDataSource dynamicDataSource) {
return new DataSourceTransactionManager(dynamicDataSource);
}
}
```
其中,我们定义了DataSourceConfig配置类,用于配置数据源和事务管理器。我们通过@Bean注解创建数据源对象并读取application.yml配置文件中的数据源信息。然后通过@Primary注解指定默认的数据源为Master数据源。最后,我们创建了DynamicDataSource对象,用于动态切换数据源,同时创建了事务管理器对象,用于管理事务。
4. 定义数据源切换注解
我们可以通过自定义注解来实现动态切换数据源。
```
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetDataSource {
DynamicDataSource.DataSourceType value() default DynamicDataSource.DataSourceType.MASTER;
}
```
其中,@TargetDataSource注解用于标记数据源类型,我们通过value()方法指定数据源类型,默认为Master数据源。
5. 定义动态数据源
我们可以通过继承AbstractRoutingDataSource类来实现动态数据源的切换。
```
public class DynamicDataSource extends AbstractRoutingDataSource {
private DataSource masterDataSource;
private Map<Object, Object> targetDataSources;
public DynamicDataSource(DataSource masterDataSource, Map<Object, Object> targetDataSources) {
this.masterDataSource = masterDataSource;
this.targetDataSources = targetDataSources;
super.setDefaultTargetDataSource(masterDataSource);
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
public enum DataSourceType {
MASTER, SLAVE
}
}
```
其中,我们定义了DynamicDataSource类,继承了AbstractRoutingDataSource类。在DynamicDataSource类中,我们重写了determineCurrentLookupKey()方法,根据当前线程的数据源类型,返回对应的数据源。我们通过枚举类型DataSourceType定义了Master和Slave两种数据源类型。
6. 实现数据源切换
我们可以通过AOP的方式,在方法执行前切换数据源。
```
@Aspect
@Component
public class DataSourceAspect {
@Pointcut("@annotation(com.example.demo.annotation.TargetDataSource)")
public void dataSourcePointCut() {
}
@Around("dataSourcePointCut()")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature) point.getSignature();
TargetDataSource dataSource = signature.getMethod().getAnnotation(TargetDataSource.class);
if (dataSource == null) {
DataSourceContextHolder.setDataSourceType(DynamicDataSource.DataSourceType.MASTER);
} else {
DataSourceContextHolder.setDataSourceType(dataSource.value());
}
try {
return point.proceed();
} finally {
DataSourceContextHolder.clearDataSourceType();
}
}
}
```
其中,我们定义了DataSourceAspect切面类,用于切换数据源。我们通过@Around注解标记了切点,在方法执行前,根据注解中指定的数据源类型,切换数据源。执行完毕后,再切换回默认的Master数据源。
7. 编写业务代码
最后,我们编写业务代码,通过@TargetDataSource注解指定数据源类型。
```
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
@TargetDataSource(DynamicDataSource.DataSourceType.MASTER)
public void addUser(User user) {
userMapper.addUser(user);
}
@Override
@TargetDataSource(DynamicDataSource.DataSourceType.SLAVE)
public User getUserById(int id) {
return userMapper.getUserById(id);
}
}
```
其中,我们定义了UserServiceImpl类,实现了UserService接口。在addUser()方法中,我们指定数据源类型为Master数据源,在getUserById()方法中,我们指定数据源类型为Slave数据源。
通过以上步骤,我们就可以实现Spring Boot多数据源的读写分离了。
阅读全文