当前位置: 首页> 娱乐> 明星 > Ruo-Yi 前后端分离如何不使用注解@DataSource的方式而是使用Mybatis插件技术实现多数据源的切换【可以根据配置文件进行开启/关闭】

Ruo-Yi 前后端分离如何不使用注解@DataSource的方式而是使用Mybatis插件技术实现多数据源的切换【可以根据配置文件进行开启/关闭】

时间:2025/8/6 2:17:40来源:https://blog.csdn.net/H_Q_Li/article/details/141558762 浏览次数:0次

Ruo-Yi 前后端分离如何不使用注解@DataSource的方式而是使用Mybatis插件技术实现多数据源的切换【可以根据配置文件进行开启/关闭】

1、首先 配置文件:

# 数据源配置
spring:datasource:type: com.alibaba.druid.pool.DruidDataSourcedriverClassName: com.mysql.cj.jdbc.Driverdruid:# 主库数据源master:url: jdbc:mysql://localhost:3306/ry-vue-master?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456# 从库数据源slave:# 从数据源开关/默认关闭enabled: trueurl: jdbc:mysql://localhost:3306/ry-vue-slave?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8username: rootpassword: 123456

配置多数据源,我们需要开启 slave 数据源。

2、定义多个数据源

/*** druid 配置多数据源** @author ruoyi*/
@Configuration
public class DruidConfig
{// 定义数据源1@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}// 定义数据源2@Bean@ConfigurationProperties("spring.datasource.druid.slave")@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")public DataSource slaveDataSource(DruidProperties druidProperties){DruidDataSource dataSource = DruidDataSourceBuilder.create().build();return druidProperties.dataSource(dataSource);}// 定义动态数据源@Bean(name = "dynamicDataSource")@Primarypublic DynamicDataSource dataSource(DataSource masterDataSource){Map<Object, Object> targetDataSources = new HashMap<>();targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");return new DynamicDataSource(masterDataSource, targetDataSources);}/*** 设置数据源** @param targetDataSources 备选数据源集合* @param sourceName 数据源名称* @param beanName bean名称*/public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName){try{DataSource dataSource = SpringUtils.getBean(beanName);targetDataSources.put(sourceName, dataSource);}catch (Exception e){}}}

3、定义动态数据源

/*** 动态数据源* 应用直接操作的是 AbstractRoutingDataSource 的实现类,告诉 AbstractRoutingDataSource 访问哪个数据库,* 然后由 AbstractRoutingDataSource 从事先配置好的数据源中选择一个数据源,来访问对应的数据库。** AbstractRoutingDataSource 属性:*      Map<Object, Object> targetDataSources;所有数据源【需指定】*      Object defaultTargetDataSource;默认数据源【需指定】*      Map<Object, DataSource> resolvedDataSources = targetDataSources** @author ruoyi*/
public class DynamicDataSource extends AbstractRoutingDataSource
{/*** 设置数据源* @param defaultTargetDataSource 默认数据源* @param targetDataSources 备选数据源*/public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources){// 设置默认数据源,未匹配则使用默认数据源super.setDefaultTargetDataSource(defaultTargetDataSource);super.setTargetDataSources(targetDataSources);super.afterPropertiesSet();}@Overrideprotected Object determineCurrentLookupKey(){return DynamicDataSourceContextHolder.getDataSourceType();}
}

4、定义mybatis插件

package com.ruoyi.framework.datasource;import com.baomidou.dynamic.datasource.spring.boot.autoconfigure.DynamicDataSourceProperties;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.ruoyi.common.enums.DataSourceType;
import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Component;@Intercepts({@Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
), @Signature(type = Executor.class,method = "query",args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
), @Signature(type = Executor.class,method = "update",args = {MappedStatement.class, Object.class}
)})
@Component
@ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true") // 为了能根据配置文件,决定是否在容器中创建插件对象
public class MyDynamicDataSourcePlugin implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("============================");System.out.println("Intercepted method: " + invocation.getMethod().getName());System.out.println("============================");Object[] args = invocation.getArgs();MappedStatement ms = (MappedStatement) args[0];String dataSource = SqlCommandType.SELECT == ms.getSqlCommandType() ? (DataSourceType.SLAVE.name()) : (DataSourceType.MASTER.name());com.ruoyi.framework.datasource.DynamicDataSourceContextHolder.setDataSourceType(dataSource);try {return invocation.proceed();} finally {com.ruoyi.framework.datasource.DynamicDataSourceContextHolder.clearDataSourceType();}}@Overridepublic Object plugin(Object target) {if (target instanceof Executor) {return Plugin.wrap(target, this);} else {return target;}}
}

你以为完了????没有一定要将这个插件注册到sqlsessionfactory里面,我在这里遇到了很大的坑,因为若依自己写了一个sqlsessionfactory,所以要找到若依写的 SqlSessionFactory,然后将我们的插件加入进去。

若依在 MyBatisConfig 里面写了一个sqlSessionFactory()方法:

    @Value("${spring.datasource.druid.slave.enabled:false}") // 为了能根据配置文件,决定是否使用插件private boolean enableDynamicDataSource; @Autowired(required = false) // 若没有开启slave数据元,容器中没有该对象了private MyDynamicDataSourcePlugin myDynamicDataSourcePlugin;@Beanpublic SqlSessionFactory sqlSessionFactory(DataSource dataSource, MyDynamicDataSourcePlugin plugin) throws Exception{String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");String mapperLocations = env.getProperty("mybatis.mapperLocations");String configLocation = env.getProperty("mybatis.configLocation");typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);VFS.addImplClass(SpringBootVFS.class);final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();sessionFactory.setDataSource(dataSource);if (enableDynamicDataSource && myDynamicDataSourcePlugin != null) {sessionFactory.setPlugins(new Interceptor[]{myDynamicDataSourcePlugin});}sessionFactory.setTypeAliasesPackage(typeAliasesPackage);sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));return sessionFactory.getObject();}

根据配置文件,实现动态添加 数据源切换插件:

if (enableDynamicDataSource && myDynamicDataSourcePlugin != null) {sessionFactory.setPlugins(new Interceptor[]{myDynamicDataSourcePlugin});}

这个时候就可以测试了。

数据库当前状态:
master:
在这里插入图片描述
slave:
在这里插入图片描述
添加一个用户:
在这里插入图片描述

添加用户后数据库状态:
页面:在这里插入图片描述
发现没有 orm,没有就对了,因为查询查询的是 slave,添加用户添加进去的是 master库

master:
在这里插入图片描述

slave:
在这里插入图片描述

关键字:Ruo-Yi 前后端分离如何不使用注解@DataSource的方式而是使用Mybatis插件技术实现多数据源的切换【可以根据配置文件进行开启/关闭】

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: