mybatisplus sql读写分离
时间: 2024-03-21 22:37:05 浏览: 202
MyBatis-Plus是一个基于MyBatis的增强工具,它提供了很多便捷的功能来简化开发。其中,MyBatis-Plus也支持SQL读写分离的配置。
SQL读写分离是指将数据库的读操作和写操作分别分配到不同的数据库实例上,以提高系统的性能和可扩展性。一般情况下,读操作比写操作频繁,通过将读操作分散到多个从库上,可以有效减轻主库的负载压力。
在MyBatis-Plus中,可以通过配置数据源和使用动态数据源来实现SQL读写分离。具体步骤如下:
1. 配置主从数据源:在配置文件中配置主库和从库的数据源信息,包括数据库连接信息、用户名、密码等。
2. 配置动态数据源:使用MyBatis-Plus提供的DynamicDataSource类来创建动态数据源,并将主库和从库的数据源添加到动态数据源中。
3. 配置读写分离策略:通过配置MyBatis-Plus的GlobalConfig对象,设置读写分离策略为动态数据源。
4. 使用注解指定读写操作:在需要进行读操作的方法上使用@Slave注解,表示该方法使用从库进行查询操作;在需要进行写操作的方法上使用@Master注解,表示该方法使用主库进行写操作。
这样配置后,MyBatis-Plus会根据方法上的注解来选择对应的数据源进行操作,实现SQL读写分离的效果。
相关问题
SpringBoot3+MyBatisPlus实现读写分离
Spring Boot 3.x版本与MyBatisPlus结合实现读写分离通常需要以下几个步骤:
1. **配置数据库连接池**:
使用如Druid、HikariCP等高可用数据库连接池,它们支持配置多个数据源,分别用于读取和写入操作。
```java
@Configuration
public class DataSourceConfig {
@Value("${spring.datasource.master.url}")
private String masterUrl;
@Value("${spring.datasource.slave.urls}")
private String[] slaveUrls;
@Bean(name = "masterDataSource")
public DataSource masterDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(masterUrl);
// 其他配置,如用户名密码、初始化大小等
return dataSource;
}
@Bean(name = "slaveDataSourceList")
List<DataSource> slaveDataSources() {
List<DataSource> list = Arrays.stream(slaveUrls)
.map(url -> {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setUrl(url);
// 配置其他属性,如监控统计拦截等
return dataSource;
})
.collect(Collectors.toList());
return list;
}
}
```
2. **配置MyBatis Plus分库分表**:
MyBatisPlus提供了`GlobalConfig`全局配置,可以在这里指定读写分离策略,比如读库切换和写库策略。同时,要配置对应的分库分表规则。
```java
@Configuration
@MapperScan("com.example.mapper")
public class GlobalConfig extends BaseGlobalConfiguration {
@Autowired
private DataSource masterDataSource;
@Autowired
private List<DataSource> slaveDataSources;
@Override
protected void globalSettings(GlobalConfigSetting config) {
// 设置读库和写库
config.masterDataSource(masterDataSource).slaveDataSources(slaveDataSources);
// 分库分表规则
config.masterTableRule(new ShardingStrategy("table_name"));
config.writeTableRule(new WriteStrategy("write_table_name", new MasterSlaveRule(slaveDataSources)));
}
}
```
3. **使用分库分表的Repository**:
MyBatisPlus提供了动态SQL的支持,可以在Repository方法上标注`@ReadSqlSource`或`@UpdateSqlSource`注解,来指定针对读库或写库的不同SQL。
```java
public interface UserMapper {
@ReadSqlSource(type = UserEntity.class, resource = "/sql/read-user.sql")
List<UserEntity> selectUsers(@Param("userId") Long userId);
@UpdateSqlSource(type = UserEntity.class, resource = "/sql/update-user.sql")
int updateUser(@Param("user") UserEntity user);
}
```
springboot+mybatisplus+druid实现读写分离
实现读写分离可以利用 SpringBoot、MybatisPlus 和 Druid 进行配置。下面是一个简单的实现过程:
1. 添加 MybatisPlus 和 Druid 的 Maven 依赖。
```xml
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.6</version>
</dependency>
```
2. 在配置文件中添加 Druid 数据源相关配置。
```yaml
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://localhost:3306/db_name?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
driver-class-name: com.mysql.cj.jdbc.Driver
type: com.alibaba.druid.pool.DruidDataSource
druid:
initialSize: 5
maxActive: 10
minIdle: 5
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxPoolPreparedStatementPerConnectionSize: 20
filters: stat,wall,log4j
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=5000
```
3. 配置 MybatisPlus 的多数据源功能。
```java
@Configuration
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource.master")
public DataSource masterDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
@ConfigurationProperties(prefix = "spring.datasource.slave")
public DataSource slaveDataSource() {
return DruidDataSourceBuilder.create().build();
}
@Bean
public DynamicDataSource dynamicDataSource(@Qualifier("masterDataSource") DataSource masterDataSource,
@Qualifier("slaveDataSource") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DataSourceType.MASTER.getType(), masterDataSource);
targetDataSources.put(DataSourceType.SLAVE.getType(), slaveDataSource);
return new DynamicDataSource(masterDataSource, targetDataSources);
}
}
```
4. 创建一个 DataSourceHolder 类,用于保存当前线程的数据源类型。
```java
public class DataSourceHolder {
private static final ThreadLocal<String> HOLDER = new ThreadLocal<>();
public static String getDataSource() {
return HOLDER.get();
}
public static void setDataSource(String dataSource) {
HOLDER.set(dataSource);
}
public static void clearDataSource() {
HOLDER.remove();
}
}
```
5. 创建一个枚举类型 DataSourceType,用于表示数据源类型。
```java
public enum DataSourceType {
MASTER("master"),
SLAVE("slave");
private final String type;
DataSourceType(String type) {
this.type = type;
}
public String getType() {
return type;
}
}
```
6. 创建一个 DynamicDataSource 类,继承 AbstractRoutingDataSource,用于动态切换数据源。
```java
public class DynamicDataSource extends AbstractRoutingDataSource {
private final Map<Object, Object> targetDataSources;
public DynamicDataSource(DataSource defaultDataSource, Map<Object, Object> targetDataSources) {
super.setDefaultTargetDataSource(defaultDataSource);
this.targetDataSources = targetDataSources;
super.setTargetDataSources(targetDataSources);
super.afterPropertiesSet();
}
@Override
protected Object determineCurrentLookupKey() {
return DataSourceHolder.getDataSource();
}
@Override
public void setTargetDataSources(Map<Object, Object> targetDataSources) {
this.targetDataSources.putAll(targetDataSources);
super.setTargetDataSources(this.targetDataSources);
super.afterPropertiesSet();
}
@Override
public void addTargetDataSource(Object key, Object dataSource) {
this.targetDataSources.put(key, dataSource);
super.setTargetDataSources(this.targetDataSources);
super.afterPropertiesSet();
}
}
```
7. 创建一个 AopDataSourceConfig 类,用于配置切面,实现动态切换数据源。
```java
@Configuration
public class AopDataSourceConfig {
@Bean
public DataSourceAspect dataSourceAspect() {
return new DataSourceAspect();
}
}
```
```java
@Aspect
public class DataSourceAspect {
@Pointcut("@annotation(com.example.demo.annotation.Master) " +
"|| execution(* com.example.demo.service..*.select*(..)) " +
"|| execution(* com.example.demo.service..*.get*(..)) " +
"|| execution(* com.example.demo.service..*.query*(..)) " +
"|| execution(* com.example.demo.service..*.find*(..)) " +
"|| execution(* com.example.demo.service..*.count*(..))")
public void read() {
}
@Pointcut("execution(* com.example.demo.service..*.insert*(..)) " +
"|| execution(* com.example.demo.service..*.update*(..)) " +
"|| execution(* com.example.demo.service..*.delete*(..))")
public void write() {
}
@Around("read()")
public Object read(ProceedingJoinPoint joinPoint) throws Throwable {
try {
DataSourceHolder.setDataSource(DataSourceType.SLAVE.getType());
return joinPoint.proceed();
} finally {
DataSourceHolder.clearDataSource();
}
}
@Around("write()")
public Object write(ProceedingJoinPoint joinPoint) throws Throwable {
try {
DataSourceHolder.setDataSource(DataSourceType.MASTER.getType());
return joinPoint.proceed();
} finally {
DataSourceHolder.clearDataSource();
}
}
}
```
8. 在 Service 层的方法上使用 @Master 注解,表示强制使用主库。
```java
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
@Override
@Master
public boolean save(User user) {
return super.save(user);
}
}
```
这样就实现了读写分离功能。需要注意的是,在使用 MybatisPlus 进行 CRUD 操作时,需要使用对应的 Service 方法,例如 selectList、selectPage、insert、updateById、deleteById,而不是直接调用 Mapper 方法。否则,数据源切换将不会生效。
阅读全文