mybatis+springboot读写分离
时间: 2024-12-31 12:41:29 浏览: 15
### 实现Spring Boot MyBatis读写分离
在Spring Boot项目中实现MyBatis的读写分离涉及配置多个数据源并合理分配读取和写入操作到不同的数据库实例。通过动态切换数据源,可以有效地分担主库的压力。
#### 配置多数据源
为了支持读写分离,在`application.yml`文件中定义两个数据源:一个是用于写的主数据源(master),另一个是用于读的从数据源(slave)。以下是具体的YAML配置:
```yaml
spring:
datasource:
master:
url: jdbc:mysql://localhost:3306/master_db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
slave:
url: jdbc:mysql://localhost:3306/slave_db?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=UTC
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
```
#### 创建自定义的数据源路由逻辑
创建一个名为`DynamicDataSourceRouter.java`类来管理不同场景下的数据源选择策略。该类实现了`AbstractRoutingDataSource`接口,并重写了其方法以决定当前线程应该使用哪个数据源。
```java
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
public class DynamicDataSourceRouter extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DataSourceContextHolder.getDataSourceType();
}
}
```
还需要有一个工具类`DataSourceContextHolder.java`用来保存当前上下文中使用的数据源名称。
```java
public class DataSourceContextHolder {
private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();
public static void setDataSourceType(String dataSourceType) {
contextHolder.set(dataSourceType);
}
public static String getDataSourceType() {
return (contextHolder.get() == null ? "master" : contextHolder.get());
}
public static void clearDataSourceType() {
contextHolder.remove();
}
}
```
#### 定义AOP切面拦截器
为了让应用程序自动区分读写请求,可以通过AOP技术设置环绕通知,在执行SQL查询之前更改默认的数据源为从库;而在更新、插入或删除记录前则恢复为主库连接。
```java
@Aspect
@Component
@Slf4j
public class DataSourceAspect {
@Around("@annotation(com.example.annotation.DataSource)")
public Object around(ProceedingJoinPoint point) throws Throwable {
MethodSignature signature = (MethodSignature)point.getSignature();
Method method = signature.getMethod();
if(method.isAnnotationPresent(DataSource.class)){
DataSource source = method.getAnnotation(DataSource.class);
log.info("Switch to {} data source",source.value());
try{
DataSourceContextHolder.setDataSourceType(source.value().name());
return point.proceed();
}finally {
DataSourceContextHolder.clearDataSourceType();
}
}
return point.proceed();
}
}
```
上述代码片段展示了如何利用面向方面的编程(AOP),使得开发者可以在不修改业务逻辑的情况下轻松控制每次访问的具体目标数据库[^1]。
阅读全文