mybatis plus 配置多数据源(数据源进行切换)
多数据源(数据源进行切换)
AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey() 决定使用哪个数据源。
1、application.yml中配置多个数据源
# Order
spring.datasource.order.url=jdbc:mysql://localhost:3306/seata_order?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.datasource.order.username=root
spring.datasource.order.password=123456
spring.datasource.order.driver-class-name=com.mysql.cj.jdbc.Driver
# Storage
spring.datasource.storage.url=jdbc:mysql://localhost:3306/seata_storage?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.datasource.storage.username=root
spring.datasource.storage.password=123456
spring.datasource.storage.driver-class-name=com.mysql.cj.jdbc.Driver
# Pay
spring.datasource.pay.url=jdbc:mysql://localhost:3306/seata_pay?useUnicode=true&characterEncoding=utf8&allowMultiQueries=true&useSSL=false
spring.datasource.pay.username=root
spring.datasource.pay.password=123456
spring.datasource.pay.driver-class-name=com.mysql.cj.jdbc.Driver
2、主启动类添加注解
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
3、编写配置类
@Getter
public enum DataSourceKey {
/**
* Order data source key.
*/
ORDER,
/**
* Storage data source key.
*/
STORAGE,
/**
* Pay data source key.
*/
PAY,
}
public class DynamicDataSourceContextHolder {
private static final ThreadLocal<String> CONTEXT_HOLDER = ThreadLocal.withInitial(DataSourceKey.ORDER::name);
private static List<Object> dataSourceKeys = new ArrayList<>();
public static void setDataSourceKey(DataSourceKey key) {
CONTEXT_HOLDER.set(key.name());
}
public static String getDataSourceKey() {
return CONTEXT_HOLDER.get();
}
public static void clearDataSourceKey() {
CONTEXT_HOLDER.remove();
}
public static List<Object> getDataSourceKeys() {
return dataSourceKeys;
}
}
public class DynamicRoutingDataSource extends AbstractRoutingDataSource {
@Override
protected Object determineCurrentLookupKey() {
//log.info("当前数据源 [{}]", DynamicDataSourceContextHolder.getDataSourceKey());
return DynamicDataSourceContextHolder.getDataSourceKey();
}
}
@Configuration
public class DataSourceProxyConfig {
@Bean("originOrder")
@ConfigurationProperties(prefix = "spring.datasource.order")
public DataSource dataSourceMaster() {
return new DruidDataSource();
}
@Bean("originStorage")
@ConfigurationProperties(prefix = "spring.datasource.storage")
public DataSource dataSourceStorage() {
return new DruidDataSource();
}
@Bean("originPay")
@ConfigurationProperties(prefix = "spring.datasource.pay")
public DataSource dataSourcePay() {
return new DruidDataSource();
}
@Bean(name = "order")
public DataSourceProxy masterDataSourceProxy(@Qualifier("originOrder") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean(name = "storage")
public DataSourceProxy storageDataSourceProxy(@Qualifier("originStorage") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean(name = "pay")
public DataSourceProxy payDataSourceProxy(@Qualifier("originPay") DataSource dataSource) {
return new DataSourceProxy(dataSource);
}
@Bean("dynamicDataSource")
public DataSource dynamicDataSource(@Qualifier("order") DataSource dataSourceOrder,
@Qualifier("storage") DataSource dataSourceStorage,
@Qualifier("pay") DataSource dataSourcePay) {
DynamicRoutingDataSource dynamicRoutingDataSource = new DynamicRoutingDataSource();
Map<Object, Object> dataSourceMap = new HashMap<>(3);
dataSourceMap.put(DataSourceKey.ORDER.name(), dataSourceOrder);
dataSourceMap.put(DataSourceKey.STORAGE.name(), dataSourceStorage);
dataSourceMap.put(DataSourceKey.PAY.name(), dataSourcePay);
dynamicRoutingDataSource.setDefaultTargetDataSource(dataSourceOrder);
dynamicRoutingDataSource.setTargetDataSources(dataSourceMap);
DynamicDataSourceContextHolder.getDataSourceKeys().addAll(dataSourceMap.keySet());
return dynamicRoutingDataSource;
}
@Bean
@ConfigurationProperties(prefix = "mybatis-plus") // MybatisSqlSessionFactoryBean中有各种MybatisPlus的配置属性(globalConfig、mapperLocations} 而SqlSessionFactoryBean中则是mybatis的各种配置属性(typeAlies、mapperLocations)
public MybatisSqlSessionFactoryBean sqlSessionFactoryBean(@Qualifier("dynamicDataSource") DataSource dataSource) {
// 这里用 MybatisSqlSessionFactoryBean 代替了 SqlSessionFactoryBean,否则 MyBatisPlus 不会生效
MybatisSqlSessionFactoryBean mybatisSqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
mybatisSqlSessionFactoryBean.setDataSource(dataSource);
return mybatisSqlSessionFactoryBean;
}
}
调用切换数据源:
@GlobalTransactional
@Override
public OperationResponse placeOrder(PlaceOrderRequestVO placeOrderRequestVO) throws Exception {
DynamicDataSourceContextHolder.setDataSourceKey(DataSourceKey.ORDER);//切换数据源
Integer amount = 1;
Integer price = placeOrderRequestVO.getPrice();
Order order = Order.builder().build();
Integer saveOrderRecord = orderDao.insert(order);
// 扣减库存
boolean operationStorageResult = storageService.reduceStock(placeOrderRequestVO.getProductId(), amount);
// 扣减余额
boolean operationBalanceResult = payService.reduceBalance(placeOrderRequestVO.getUserId(), price);
DynamicDataSourceContextHolder.setDataSourceKey(DataSourceKey.ORDER);//切换数据源
order.setStatus(OrderStatus.SUCCESS);
Integer updateOrderRecord = orderDao.updateById(order);
return success(operationStorageResult && operationBalanceResult);
}
项目启动报错:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured
原因:导入spring-mybatis依赖后,springboot启动时会自动加载数据源,由于dataSource配置成多数据源加载不到spring.datasource.url故而报错。
解决:1、主启动类添加@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
2、若上面配置还是无法解决,可以配置一个默认数据源让其启动时加载(不影响,会被多数据源切换时覆盖的):spring.datasource.url
额外:
SqlSessionFactory factory=new SqlSessionFactoryBuilder().build(in);
SqlSession sqlSession=factory.openSession(); //sqlSession就是用来操作sql语句的
使用 MyBatis-Spring 之后, 会使用SqlSessionFactoryBean来代替SqlSessionFactoryBuilder创建SqlSessionFactory
MybatisPlus需要使用MybatisSqlSessionFactoryBean。
相关文章:
mybatis plus 配置多数据源(数据源进行切换)
多数据源(数据源进行切换) AbstractRoutingDataSource 根据用户定义的规则选择当前的数据源,这样我们可以在执行查询之前,设置使用的数据源。实现可动态路由的数据源,在每次数据库查询操作前执行。它的抽象方法 determineCurrentLookupKey()…...
Docker-Android安卓模拟器本地部署并实现远程开发测试
文章目录 1. 虚拟化环境检查2. Android 模拟器部署3. Ubuntu安装Cpolar4. 配置公网地址5. 远程访问小结 6. 固定Cpolar公网地址7. 固定地址访问 本文主要介绍如何在Ubuntu系统使用Docker部署docker-android安卓模拟器,并结合cpolar内网穿透工具实现公网远程访问本地…...
vue-封装上下(垂直方向)轮播
需求:没有找到特别好的上下轮播插件-所以自己写了一个简单的demo 一.上下平滑轮播-移入停止-移出继续轮播 <!--* 消息滚动 --> <template><div class"news"><div id"roll" class"InfoBox" mouseover"thi…...
海外私人IP和原生IP有什么区别,谁更有优势?
一、什么是海外私人IP?什么是原生IP? 1、海外私人IP: 海外私人IP是由专门的服务提供商提供的IP地址,这些IP地址通常与特定地理位置或国家相关联。这些IP地址独享私人而不用与其他用户共享。海外私人IP广泛应用与跨境电商中&#x…...
主流容器工具对比以及重点推荐学习的企业级工具
常见的主流容器工具包括但不限于以下几种: 1. Docker: Docker 是最流行的容器平台之一,它允许开发者将应用及其依赖打包到一个轻量级、可移植的容器中,然后可以在任何支持Docker的系统上运行。 2. Kubernetes:Kubern…...
国产linux系统(银河麒麟,统信uos)使用 PageOffice 国产版在线编辑word文件,同时保存数据和文件
PageOffice 国产版 :支持信创系统,支持银河麒麟V10和统信UOS,支持X86(intel、兆芯、海光等)、ARM(飞腾、鲲鹏、麒麟等)芯片架构。 在OA办公、文档流转等各个Web系统中,实现最简单的…...
个人感觉对Material设计有用的几个网址
(一) Modular and customizable Material Design UI components for Android GIthub: material-components-android (二) 学习Material设计 Material Design (三) 用于创建Material主题,支持导出多种格式 material-theme-builder...
ubuntu18 安装sudo
ubuntu18 安装sudo 在Ubuntu 18.04上安装sudo通常是不必要的,因为sudo是Ubuntu及其衍生版本的基本包之一,默认情况下就已经安装。如果出于某种原因,sudo没有预装或者你需要升级到最新版本,你可以通过以下命令安装或更新它&#x…...
【力扣一轮】202.快乐数 1.两数之和
202.快乐数 力扣链接 代码随想录链接 思路 看到这一题没思路,直接看题解。 发现其中一个难点在于“无限循环”,这个字眼可以转换成退出条件。退出条件就有两种,一种是这个数字是快乐数,一种是这个数字不是快乐数。 如果是快…...
Vue小程序项目知识积累(二)
1.wx.reLaunch(Object object) 关闭所有页面,打开到应用内的某个页面。 wx.reLaunch({url:/pages/positons/index}) 参数说明: 属性类型默认值必填说明urlstring是需要跳转的应用内页面路径 (代码包路径),路径后可以带参数。参数与路径之…...
RK3588 Android13 预安装自己的apk应用及把这个应用设置为默认桌面
1、cp -rf device/rockchip/rk3588/rk3588m_s/preinstall device/rockchip/rk3588/rk3588_t/ 2、给device/rockchip/rk3588/rk3588_t/preinstall/的存放app的文件夹改名为app-imms2,在app-imms2放入app-imms2.apk,编译安卓源码即可, 3、编译完会在out/…...
NLP(16)--生成式任务
前言 仅记录学习过程,有问题欢迎讨论 输入输出均为不定长序列(seq2seq)自回归语言模型: x 为 str[start : end ]; y为 [start1 : end 1] 同时训练多个字,逐字计算交叉熵 encode-decode结构: Encoder将输…...
直播回放| 机器人任务挑战赛线上培训资料合集
大赛培训回顾 5月22日,卓翼飞思实验室为全国各赛区精心组织的机器人任务挑战赛(无人协同系统)线上培训第三期顺利落下帷幕,吸引300余人参与。本次培训主要针对仿真平台的基本使用,从仿真平台获取激光雷达/视觉数据&am…...
flask Web应用的接口调试
以上上一篇 Docker部署Azure chatgpt样例应用_群晖部署chatgpt-CSDN博客 xx为例 在app.py最下方有 /conversation 接口 在api.ts文件中可见调用了 /conversation 接口。 使用chrom浏览器F12查看 Networ- 本地运行后,使用postman调试。接口地址填写 http://127.0…...
简单易懂的 API 集成测试方法
简介:API 集成测试的重要性 API 集成测试是一类测试活动,用于验证 API 是否满足功能性、可靠性、性能和安全性等方面的预期要求。在多 API 协作的应用程序中,这种测试尤为紧要。 在这一阶段,我们不仅审视单个组件,还…...
leetcode 239. 滑动窗口最大值、347.前 K 个高频元素
leetcode 239. 滑动窗口最大值、347.前 K 个高频元素 leecode 239. 滑动窗口最大值 题目链接 :https://leetcode.cn/problems/sliding-window-maximum/description/ 题目 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的…...
npm常用指令
基础 命令:run 解释:运行脚本 示例:npm run dev 命令:list || ls 解释:查看依赖列表 示例:npm list || npm ls 命令:install || i 解释:安装依赖 示例:npm install ||…...
数字孪生技术在管理中有哪些实际应用?
随着科学技术的不断提高,数字孪生技术也在不断的从理论应用至现实,并且涉及领域较为广泛。 在生产运营管理层面,通过构建数字孪生模型,企业可以精准模拟和优化生产线,实现生产流程的智能化和高效化。比如,…...
LeetCode/NowCoder-链表经典算法OJ练习3
孜孜不倦:孜孜:勤勉,不懈怠。指工作或学习勤奋不知疲倦。💓💓💓 目录 说在前面 题目一:返回倒数第k个节点 题目二:链表的回文结构 题目三:相交链表 SUMUP结尾 说在前…...
如何理解HTML语义化
如何理解HTML语义化 HTML语义化,简单来说,就是使用HTML标签来清晰地表达页面内容的结构和意义,而不仅仅是作为布局的容器。它强调使用具有明确含义的HTML标签来描述页面元素,而不是仅仅依赖CSS来实现页面的外观和布局。 理解HTM…...
15、深拷贝浅拷贝的区别?如何实现一个深拷贝?
目录 一、先说本质区别 二、从内存角度理解 三、浅拷贝是什么 常见浅拷贝方式 1. Object.assign 2. 展开运算符 ... 3. 数组方法 四、深拷贝是什么 五、常见深拷贝实现方式 1. JSON.parse(JSON.stringify(obj)) 优点 缺点 无法处理: 2. structuredClo…...
基于特高压张北柔性直流输电四端系统真实参数的PSCAD仿真平台精准搭建方法与技术要点解析
张北柔直工程四端pscad模型,实际参数搭建昨天啃了半周的张北柔直四端可研PSCAD用户手册补录参数的间隙,把自己攒的模块线搭顺,终于出了第一波接近稳态的交流母线波形——连误差都卡在可研给的0.5kV内,敲敲键盘,得捋捋这…...
从报错到解决:ipmitool lan与lanplus接口区别详解(避坑指南)
从报错到解决:ipmitool lan与lanplus接口区别详解(避坑指南) 在服务器带外管理的日常运维中,ipmitool是工程师们不可或缺的利器。但你是否遇到过这样的场景:明明参数正确,却因一个简单的接口类型选择错误而…...
项目介绍 MATLAB实现基于豹群算法(LVO)进行无人机三维路径规划的详细项目实例(含模型描述及部分示例代码) 专栏近期有大量优惠 还请多多点一下关注 加油 谢谢 你的鼓励是我前行的动力 谢谢支持
MATLAB实现基于豹群算法(LVO)进行无人机三维路径规划的详细项目实例 更多详细内容可直接联系博主本人 或者访问对应标题的完整博客或者文档下载页面(含完整的程序,GUI设计和代码详解) 无人机(UAV&#…...
从arctanx到指数函数:手把手教你用泰勒展开分析复杂函数渐近线
从arctanx到指数函数:手把手教你用泰勒展开分析复杂函数渐近线 数学分析中,函数渐近线的研究往往能揭示函数在无穷远处的行为特征。对于arctanx、指数函数这类常见但特性复杂的函数,泰勒展开提供了一种强有力的分析工具。本文将带你从基础概念…...
socket.io-redis-adapter迁移指南:从socket.io-redis平滑升级到新版本
socket.io-redis-adapter迁移指南:从socket.io-redis平滑升级到新版本 【免费下载链接】socket.io-redis-adapter Adapter to enable broadcasting of events to multiple separate socket.io server nodes. 项目地址: https://gitcode.com/gh_mirrors/so/socket.…...
解锁B站直播自由:第三方推流工具深度技术解析
解锁B站直播自由:第三方推流工具深度技术解析 【免费下载链接】bilibili_live_stream_code 用于在准备直播时获取第三方推流码,以便可以绕开哔哩哔哩直播姬,直接在如OBS等软件中进行直播,软件同时提供定义直播分区和标题功能 项…...
智能SQL工具全攻略:从自然语言到高效数据查询的技术实践
智能SQL工具全攻略:从自然语言到高效数据查询的技术实践 【免费下载链接】sqlcoder SoTA LLM for converting natural language questions to SQL queries 项目地址: https://gitcode.com/gh_mirrors/sq/sqlcoder 在数据驱动决策的时代,智能SQL工…...
已过期域名对SEO优化有什么影响
已过期域名对SEO优化有什么影响 在当今数字化时代,网站的搜索引擎优化(SEO)对于吸引流量和提升品牌知名度至关重要。域名作为网站的身份标志,其质量和历史往往对SEO有着深远影响。本文将探讨已过期域名对SEO优化有什么影响&#…...
小白也能轻松上手!通义千问2.5-7B+Ollama快速入门
小白也能轻松上手!通义千问2.5-7BOllama快速入门 1. 为什么选择通义千问2.5-7B? 通义千问2.5-7B-Instruct是阿里云2024年9月发布的中等规模开源大模型,拥有70亿参数,专为指令跟随任务优化。这个模型特别适合想在本地运行AI但又不…...
