使用 Mybatis-Plus 实现 MySQL 数据库读写分离需要进行如下步骤:
1.添加Mybatis-Plus的依赖
在 pom.xml 文件中添加 Mybatis-Plus 的依赖,例如:
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.1</version>
</dependency>
2.配置数据源
在 Spring Boot 项目的配置文件 application.properties 或 application.yml 中,配置主数据库和从数据库的数据源信息,例如:
# 主数据库
spring.datasource.master.url = jdbc:mysql://localhost:3306/db_master?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.master.username = root
spring.datasource.master.password = 123456
spring.datasource.master.driver-class-name = com.mysql.cj.jdbc.Driver
# 从数据库
spring.datasource.slave.url = jdbc:mysql://localhost:3306/db_slave?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false
spring.datasource.slave.username = root
spring.datasource.slave.password = 123456
spring.datasource.slave.driver-class-name = com.mysql.cj.jdbc.Driver
3.配置 Mybatis-Plus
在 Spring Boot 项目的配置文件中,配置 Mybatis-Plus 的相关选项,例如:
mybatis-plus:
mapper-locations: classpath*:mapper/*.xml
type-aliases-package: com.example.domain
global-config:
db-config:
id-type: auto
logic-delete-field: deleted
logic-delete-value: 1
logic-not-delete-value: 0
configuration:
map-underscore-to-camel-case: true
cache-enabled: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
4.配置读写分离
在 Spring Boot 项目的配置文件中,可以通过配置 Mybatis-Plus 的 AbstractRoutingDataSource 实现读写分离,例如:
@Configuration
public class DataSourceConfig {
@Bean(name = "master")
@ConfigurationProperties("spring.datasource.master")
public DataSource masterDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "slave")
@ConfigurationProperties("spring.datasource.slave")
public DataSource slaveDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "dynamicDataSource")
public AbstractRoutingDataSource dynamicDataSource(@Qualifier("master") DataSource masterDataSource,
@Qualifier("slave") DataSource slaveDataSource) {
Map<Object, Object> targetDataSources = new HashMap<>();
targetDataSources.put(DatasourceType.MASTER.name(), masterDataSource);
targetDataSources.put(DatasourceType.SLAVE.name(), slaveDataSource);
DynamicDataSource dataSource = new DynamicDataSource();
dataSource.setTargetDataSources(targetDataSources);
dataSource.setDefaultTargetDataSource(masterDataSource);
return dataSource;
}
}
其中,DynamicDataSource 继承 AbstractRoutingDataSource 并实现了 determineCurrentLookupKey 方法,根据需要路由到主数据库或从数据库。
5.实现多数据源
创建一个 DatasourceType 的枚举类,定义主从数据源的类型,例如:
public enum DatasourceType {
MASTER,
SLAVE
}
创建一个 DynamicDataSource 类,继承 AbstractRoutingDataSource,并实现 determineCurrentLookupKey 方法,根据需要路由到主数据库或从数据库;同时,在方法中实现数据源的切换:
public class DynamicDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
return DatasourceContextHolder.getDatasourceType();
}
@Override
public Connection getConnection() throws SQLException {
String dsKey = (String) determineCurrentLookupKey();
if (dsKey != null && !dsKey.isEmpty()) {
DataSource dataSource = determineTargetDataSource();
if (dataSource == null) {
throw new IllegalStateException("数据源不存在:" + dsKey);
}
return dataSource.getConnection();
} else {
return super.getConnection();
}
}
}
6.实现数据源的动态切换
在执行数据库操作前,将数据源类型存储在 ThreadLocal 变量中,并在数据源有变更时更新该变量:
public class DatasourceContextHolder {
private static final ThreadLocal<String> DATASOURCE_TYPE = ThreadLocal.withInitial(() -> DatasourceType.MASTER.name());
public static String getDatasourceType() {
return DATASOURCE_TYPE.get();
}
public static void setDatasourceType(String datasourceType) {
DATASOURCE_TYPE.set(datasourceType);
}
public static void clearDatasourceType() {
DATASOURCE_TYPE.remove();
}
}
7.实现 Mybatis-Plus 的拦截器
Mybatis-Plus 支持自定义拦截器,可以在拦截器中动态地设置数据源类型。在拦截器中实现 Intercept 方法,并在其中设置要使用的数据源类型:
public class DynamicDataSourceInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(DynamicDataSourceInterceptor.class);
@Override
public Object intercept(Invocation invocation) throws Throwable {
MethodSignature methodSignature = (MethodSignature) invocation.getSignature();
Class<?> mapperClass = methodSignature.getDeclaringType();
Method method = methodSignature.getMethod();
DataSource dataSourceAnnotation = AnnotationUtils.findAnnotation(mapperClass, DataSource.class);
if (dataSourceAnnotation == null) {
dataSourceAnnotation = AnnotationUtils.findAnnotation(method, DataSource.class);
}
if (dataSourceAnnotation != null) {
DatasourceContextHolder.setDatasourceType(dataSourceAnnotation.value().name());
logger.debug("设置数据源类型:{}", dataSourceAnnotation.value());
} else {
logger.debug("未设置数据源类型,使用默认数据源:{}", DatasourceType.MASTER);
}
try {
return invocation.proceed();
} finally {
DatasourceContextHolder.clearDatasourceType();
}
}
@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
}
}
其中,DataSource 注解用于指定要使用的数据源类型,例如:
@DataSource(DatasourceType.SLAVE)
public interface UserMapper extends BaseMapper<User> {
// ...
}
最后,在 Mybatis-Plus 的配置文件中,注册拦截器:
@Configuration
public class MybatisPlusConfig {
@Bean
public Interceptor dynamicDataSourceInterceptor() {
return new DynamicDataSourceInterceptor();
}
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(Interceptor[] interceptors) {
MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
mybatisPlusInterceptor.setInterceptors(interceptors);
return mybatisPlusInterceptor;
}
}
通过以上步骤,就可以在 Spring Boot 项目中使用 Mybatis-Plus 实现 MySQL 数据库的读写分离了。