springboot配置多数据源以及事务问题

一、背景以及为什么需要学习

在高并发的项目中,单数据库已无法承载大数据量的访问,因此需要使用多个数据库进行对数据的读写分离,此外就是在微服化的今天,我们在项目中可能采用各种不同存储,因此也需要连接不同的数据库,居于这样的背景,这里简单分享实现的思路以及实现方案

二、实现方式

多数据源实现思路有两种,一种是通过配置多个SqlSessionFactory实现多数据源;

1、通过配置多个SqlSessionFactory实现多数据源在这里插入图片描述

2、通过Spring提供的AbstractRoutingDataSource抽象了一个DynamicDataSource实现动态切换数据源

在这里插入图片描述

三、方式一:不同库的Mapper指定不同的SqlSessionFactory

1 针对不同的库分别放置对用不同的SqlSessionFactory

UserDataSourceConfiguration

@Configuration
@MapperScan(basePackages = "org.datasource.demo1.usermapper",sqlSessionFactoryRef = "userSqlSessionFactory")
public class UserDataSourceConfiguration {public static final String MAPPER_LOCATION = "classpath:usermapper/*.xml";@Primary@Bean("userDataSource")@ConfigurationProperties(prefix = "spring.datasource.user")public DataSource userDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "userTransactionManager")@Primarypublic PlatformTransactionManager userTransactionManager(@Qualifier("userDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Primary@Bean(name = "userSqlSessionFactory")public SqlSessionFactory userSqlSessionFactory(@Qualifier("userDataSource") DataSource dataSource) throws Exception {final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();sessionFactoryBean.setDataSource(dataSource);sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(UserDataSourceConfiguration.MAPPER_LOCATION));return sessionFactoryBean.getObject();}}

SoulDataSourceConfiguration

@Configuration
@MapperScan(basePackages = "org.datasource.demo1.soulmapper",sqlSessionFactoryRef = "soulSqlSessionFactory")
public class SoulDataSourceConfiguration {public static final String MAPPER_LOCATION = "classpath:soulmapper/*.xml";@Bean("soulDataSource")@ConfigurationProperties(prefix = "spring.datasource.soul")public DataSource soulDataSource() {return DataSourceBuilder.create().build();}@Bean(name = "soulTransactionManager")public PlatformTransactionManager soulTransactionManager(@Qualifier("soulDataSource") DataSource dataSource) {return new DataSourceTransactionManager(dataSource);}@Bean(name = "soulSqlSessionFactory")public SqlSessionFactory soulSqlSessionFactory(@Qualifier("soulDataSource") DataSource dataSource) throws Exception {final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();sessionFactoryBean.setDataSource(dataSource);sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(SoulDataSourceConfiguration.MAPPER_LOCATION));return sessionFactoryBean.getObject();}}

2 使用和测试

@Service
public class AppAuthService {@Autowiredprivate AppAuthMapper appAuthMapper;@Transactional(rollbackFor = Exception.class)public int getCount() {int a = appAuthMapper.listCount();int b = 1 / 0;return a;}}@SpringBootTest
@RunWith(SpringRunner.class)
public class TestDataSource {@Autowiredprivate AppAuthService appAuthService;@Autowiredprivate SysUserService sysUserService;@Testpublic void test_dataSource1(){int b=sysUserService.getCount();int a=appAuthService.getCount();}
}

3 总结

此种方式使用起来分层明确,不存在任何冗余代码,不足地方就是每个库都需要对应一个配置类,该配置类中实现方式都基本类似,该种解决方案每个配置类中都存在事务管理器,因此不需要单独再去额外的关注。在使用时需要指定事务管理器

四、AOP+自定义注解

关于采用Spring AOP方式实现原理就是把多个数据源存储在一个 Map中,当需要使用某个数据源时,从 Map中获取此数据源进行处理。
在这里插入图片描述

1 AbstractRoutingDataSource

在Spring中提供了AbstractRoutingDataSource来实现此功能,继承AbstractRoutingDataSource类并覆写其determineCurrentLookupKey()方法就可以完成数据源切换,该方法只需要返回数据源key即可,也就是存放数据源的Map的key,接下来我们来看一下AbstractRoutingDataSource整体的继承结构,看他是如何做到的。
在这里插入图片描述
在整体的继承结构上我们会发现AbstractRoutingDataSource最终是继承于DataSource,因此当我们继承AbstractRoutingDataSource是我们自身也是一个数据源,对于数据源必然有连接数据库的动作,如下代码:

public Connection getConnection() throws SQLException {return this.determineTargetDataSource().getConnection();
}public Connection getConnection(String username, String password) throws SQLException {return this.determineTargetDataSource().getConnection(username, password);
}

只是AbstractRoutingDataSource的getConnection()方法里实际是调用determineTargetDataSource()返回的数据源的getConnection()方法。

protected DataSource determineTargetDataSource() {Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");Object lookupKey = this.determineCurrentLookupKey();DataSource dataSource = (DataSource)this.resolvedDataSources.get(lookupKey);if (dataSource == null && (this.lenientFallback || lookupKey == null)) {dataSource = this.resolvedDefaultDataSource;}if (dataSource == null) {throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");} else {return dataSource;}
}

该方法通过determineCurrentLookupKey()方法获取一个key,通过key从resolvedDataSources中获取数据源DataSource对象。determineCurrentLookupKey()是个抽象方法,需要继承AbstractRoutingDataSource的类实现;而resolvedDataSources是一个Map<Object, DataSource>,里面应该保存当前所有可切换的数据源。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/712998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

点亮城市名片丨计讯物联智慧灯杆系统在通讯基地的成功应用

项目背景 在国家新型城镇化大背景下&#xff0c;十四五规划纲要强调“加快数字化发展&#xff0c;建设数字中国”&#xff0c;明确提出“以数字化助推城乡发展和治理模式创新”&#xff0c;全面提高城市的运行效率和宜居程度。 项目概况 为满足灯杆灯光亮度的远程智能管理、对…

记录 android studio 通过安装NDK 编译C文件,得到需要的so文件

只怪自己太健忘&#xff0c;每次网上查了一圈&#xff0c;搞定后&#xff0c;再遇到又发现不会操作了&#xff0c;特此记下 不废话直接上步骤 &#xff08;1&#xff09; 进入AS的settinging如下界面 &#xff08;2&#xff09;选中图片箭头两个文件 进行下载 &#xff08;…

【知识管理】假设检验pvalue的计算

让我们通过一个具体的例子来解释P值的计算过程&#xff0c;假设我们有一个模型用于区分SCD&#xff08;亚临床痴呆&#xff09;和HC&#xff08;健康对照&#xff09;的分裂。我们通过置换测试来计算模型性能的P值。 原始模型性能评估 首先&#xff0c;我们在原始数据集上运行…

web学习笔记(二十一)

目录 1.构造函数创建对象 1.1规则 1.2 new关键字调用构造函数时&#xff0c;函数内部做了什么事情&#xff1f; 1.3总结 2.混合模式创建对象 3.JavaScript 继承---借助构造函数 4.原型链 4.1原型链实现方法继承 5.完美的组合继承 6.call方法的使用 1.构造函数创建对象…

React之数据绑定以及表单处理

一、表单元素 像<input>、<textarea>、<option>这样的表单元素不同于其他元素&#xff0c;因为他们可以通过用户交互发生变化。这些元素提供的界面使响应用户交互的表单数据处理更加容易 交互属性&#xff0c;用户对一下元素交互时通过onChange回调函数来监听…

回溯例题(leetcode17/37)

文章目录 leetcode37leetcode17 回溯跟枚举差不多。要注意“回溯”&#xff0c;别忘记“回”之前把之前的改动都复原。 leetcode37 leetcode37是解数独问题。本题保证有且仅有唯一解。 思路&#xff1a;先把空格子的位置存下来&#xff0c;然后对每一个空位置挨个枚举1-9。枚…

Excel常用公式总结非常实用

16个最实用的Excel万能公式 1、多条件判断 IF(And(条件1,条件2..条件N),条件成立返回值) IF(or(条件1,条件2..条件N),条件成立返回值) 2、多条件查找 Lookup(1,0/((条件1*条件2*...条件N)),返回值区域&#xff09; 3、多条件求和 Sumifs(值区域,判断区域1,条件1,判断区域2,条…

Java 数据库面试题解析(下)

20. Hash索引和B树索引的区别&#xff1f;【重点】 hash索引&#xff1a;等值查询效率高&#xff0c;不能排序&#xff0c;不能进行范围查询&#xff1b; B树索引&#xff1a;数据有序&#xff0c;适合范围查询。 21. MySQL中三种锁的级别&#xff1f;【了解】 表级锁&…

2024最新精华版Java面试题之spring篇

目录 一、Java面试题之spring篇 1、什么是spring? 2、你们项目中为什么使用Spring框架&#xff1f; 3、 Autowired和Resource关键字的区别&#xff1f; 4、依赖注入的方式有几种&#xff0c;各是什么? 5、讲一下什么是Spring容器&#xff1f; 6、说说你对Spring MVC的理…

Java毕业设计-基于springboot开发的私人健身与教练预约系统-毕业论文+答辩PPT(有源代码)

文章目录 前言一、毕设成果演示&#xff08;源代码在文末&#xff09;二、毕设摘要展示1.开发说明2.需求分析3、系统功能结构 三、系统实现展示1、系统功能模块2、后台功能模块2.1管理员功能2.2用户功能2.3教练功能 四、毕设内容和源代码获取总结 [Java毕业设计-基于springboot…

Android 11.0 内置google tts语音包功能实现

1.前言 在11.0的系统rom产品开发中,在gms的相关项目对于文字转语音包功能不是内置功能,需要自己下载google的tts语音包,然后内置,在设置 google tts语音包apk作为默认的tts语音引擎功能,接下来分析实现这个功能 2.内置google tts语音包功能实现的核心类 frameworks/ba…

Chat GPT4.0:开启智能对话的新纪元

介绍 Chat GPT4.0是基于GPT4.0架构开发的一款强大的智能对话模型。作为人工智能领域的最新进展&#xff0c;Chat GPT4.0引领着智能对话技术的新纪元。本文将探讨Chat GPT4.0的创新之处以及对智能对话发展的推动作用。 Chat GPT4.0的创新之处 Chat GPT4.0在前一版本的基础上进…

c++知识点之 --引用

本质&#xff1a;给变量起别名 语法&#xff1a;数据类型 &别名 原名 特点&#xff1a;传引用比传值的效率高很多 注意事项&#xff1a; 引用必须初始化&#xff0c;且初始化不能为空。引用不能改变引用关系&#xff08;引用的底层是指针常量&#xff08;type * const …

前端 JS 经典:for-in 和 for-of 用法区别

1. for-in 对于 string, object, array 类型使用 for-in const str "qwe"; const arr ["yqcoder", "db"]; const obj {name: "yqcoder",age: 18, };for (let i in str) {console.log(i); // 0 1 2 } for (let i in arr) {console…

简单数据类型和复杂数据类型

1. 简单数据类型 null是个特例: 2. 复杂数据类型 3. 堆和栈 注意&#xff1a; JavaScript 中是没有堆和栈的概念的&#xff0c;通过堆栈的概念可以更好的理解代码的一些执行方式&#xff0c;便于将来学习其他语言。 4. 简单数据类型传参 总结&#xff1a;简单数据类型传参传…

webview_h5与原生增加权限索取行为交互(Flutter)

应各大应用市场上架要求,增加权限索取行为用户交互弹窗 详细: https://developer.huawei.com/consumer/cn/doc/app/FAQ-faq-05#h1-1698326401789-0 flutter端使用permission_handler申请权限注册一个MethodChannel,增加一个函数,提供安卓webview相机/麦克风等权限被触发时回调…

C++写入和读取结构体到二进制文件

二进制文件速度快&#xff0c;空间效率高 写入数据到二进制文件 #include<iostream> #include<fstream> using namespace std; int main() {// 定义一个结构体struct student{int id; // 学号char name[20]; // 姓名double score; // 成…

LeetCode 2369.检查数组是否存在有效划分:动态规划(DP)

【LetMeFly】2369.检查数组是否存在有效划分&#xff1a;动态规划(DP) 力扣题目链接&#xff1a;https://leetcode.cn/problems/check-if-there-is-a-valid-partition-for-the-array/ 给你一个下标从 0 开始的整数数组 nums &#xff0c;你必须将数组划分为一个或多个 连续 子…

在线ai写作,让你随时随地创作优质内容

如今的ai技术已经渗透到我们生活的方方面面。其中&#xff0c;AI写作成为了一个备受关注的领域。如今&#xff0c;我们可以利用在线ai写作在任何时间、任何地点创作出优质的内容。 传统的写作过程需要大量的时间和精力。从构思到写作再到修改&#xff0c;每一个环节都需要我们投…

Linux进程管理——top字段

目录 1.top下半部分——进程状态 2.top常用内部命令 3.top指定 ①top ②top -d 1 ③top -d 1 -p 10126 ④top -d 1 -p 10126,1 4.使用信号控制进程 1.top下半部分——进程状态 PID&#xff1a;进程号 User&#xff1a;用户 PR/NI&#xff1a;优先级 VIRT&#xff08…