文章目录

    • 1. 引入依赖
    • 2. 配置数据源
    • 3. 配置MyBatis-Plus
    • 4. 实现动态数据源
    • 5. 实现动态数据源拦截器
    • 6. 实现自定义注解
    • 7. 使用注解标记只读操作

个人主页:程序员 小侯
CSDN新晋作者
欢迎 点赞✍评论⭐收藏
✨收录专栏:Java框架
✨文章内容:Spring Boot + MyBatis-Plus
希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!

在现代应用程序的开发中,数据库读写分离是一种常见的优化手段,能够提升系统的性能和可扩展性。本文将介绍如何使用Spring Boot和MyBatis-Plus实现数据库读写分离,并提供详细的代码示例。

1. 引入依赖

首先,在pom.xml文件中添加Spring Boot和MyBatis-Plus的依赖:

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.baomidou</groupId><artifactId>mybatis-plus-boot-starter</artifactId><version>3.4.2</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.23</version></dependency></dependencies>

2. 配置数据源

application.propertiesapplication.yml中配置主从数据源:

# 主数据源配置spring.datasource.master.url=jdbc:mysql://master-host:3306/master_dbspring.datasource.master.username=master_userspring.datasource.master.password=master_passwordspring.datasource.master.driver-class-name=com.mysql.cj.jdbc.Driver# 从数据源配置spring.datasource.slave.url=jdbc:mysql://slave-host:3306/slave_dbspring.datasource.slave.username=slave_userspring.datasource.slave.password=slave_passwordspring.datasource.slave.driver-class-name=com.mysql.cj.jdbc.Driver

3. 配置MyBatis-Plus

创建MyBatisPlusConfig类,配置MyBatis-Plus的分页插件和多数据源:

@Configuration@MapperScan("com.example.mapper")public class MyBatisPlusConfig {@Primary@Bean("masterDataSource")@ConfigurationProperties(prefix = "spring.datasource.master")public DataSource masterDataSource() {return DataSourceBuilder.create().build();}@Bean("slaveDataSource")@ConfigurationProperties(prefix = "spring.datasource.slave")public DataSource slaveDataSource() {return DataSourceBuilder.create().build();}@Beanpublic MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) throws Exception {MybatisSqlSessionFactoryBean sessionFactoryBean = new MybatisSqlSessionFactoryBean();sessionFactoryBean.setDataSource(masterDataSource);sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));MybatisConfiguration configuration = new MybatisConfiguration();configuration.setMapUnderscoreToCamelCase(true);configuration.setCacheEnabled(false);Interceptor[] interceptors = new Interceptor[]{new PaginationInterceptor(),new DynamicDataSourceInterceptor()};configuration.setInterceptors(interceptors);sessionFactoryBean.setConfiguration(configuration);return sessionFactoryBean;}@Beanpublic PlatformTransactionManager platformTransactionManager(@Qualifier("masterDataSource") DataSource masterDataSource,@Qualifier("slaveDataSource") DataSource slaveDataSource) {return new DataSourceTransactionManager(masterDataSource, slaveDataSource);}}

在上述配置中,我们使用了DynamicDataSourceInterceptor拦截器,它实现了MyBatis的Interceptor接口,用于动态切换数据源。

4. 实现动态数据源

创建DynamicDataSource类,用于动态获取当前线程的数据源:

public class DynamicDataSource extends AbstractRoutingDataSource {@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSourceKey();}}

创建DynamicDataSourceContextHolder类,用于设置和获取当前线程的数据源:

public class DynamicDataSourceContextHolder {private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();public static void setDataSourceKey(String dataSourceKey) {CONTEXT_HOLDER.set(dataSourceKey);}public static String getDataSourceKey() {return CONTEXT_HOLDER.get();}public static void clearDataSourceKey() {CONTEXT_HOLDER.remove();}}

5. 实现动态数据源拦截器

创建DynamicDataSourceInterceptor拦截器,用于在执行SQL前动态切换数据源:

public class DynamicDataSourceInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {boolean clearFlag = false;Signature signature = invocation.getSignature();if (signature instanceof MethodSignature) {MethodSignature methodSignature = (MethodSignature) signature;if (methodSignature.getMethod().isAnnotationPresent(ReadOnly.class)) {DynamicDataSourceContextHolder.setDataSourceKey("slaveDataSource");clearFlag = true;}}try {return invocation.proceed();} finally {if (clearFlag) {DynamicDataSourceContextHolder.clearDataSourceKey();}}}@Overridepublic Object plugin(Object target) {return Plugin.wrap(target, this);}@Overridepublic void setProperties(Properties properties) {// 暂时不需要配置}}

在上述代码中,我们通过@ReadOnly注解标记只读操作,从而触发数据源切换。

6. 实现自定义注解

创建ReadOnly注解,用于标记只读操作:

@Target({ElementType.METHOD, ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documentedpublic @interface ReadOnly {}

7. 使用注解标记只读操作

在Service层的方法上使用@ReadOnly注解标记只读操作:

@Servicepublic class UserService {@Autowiredprivate UserMapper userMapper;@ReadOnlypublic List<User> getAllUsers() {return userMapper.selectList(null);}// 其他方法}

通过以上步骤,我们成功地实现了Spring Boot与MyBatis-Plus的数据库读写分离。在只读操作上使用@ReadOnly注解,拦截器会动态切换到从数据源,从而提升了系统的查询性能。

这种方式的优点在于配置简单,只需要在只读操作上添加注解即可。同时,该方案也具备一定的灵活性,可以根据实际情况进行调整和

扩展。在高并发的系统中,数据库读写分离是提升性能的有效手段之一,通过本文的介绍,相信读者能够在实际项目中成功应用这一技术。

后记 美好的一天,到此结束,下次继续努力!欲知后续,请看下回分解,写作不易,感谢大家的支持!!