看京东架构师如何解决,数据库读写分离与事务纠缠的坑

2023-10-26

本篇文章讨论在数据库读写分离时使用事务的那些坑:

1. 在读写分离时会不会造成事务主从切换错误

一个线程在Serivcie时Select时选择的是从库,DynamicDataSourceHolder中ThreadLocal对应线程存储的是slave,然后调用Manager时进入事务,事务使用默认的transacatinManager关联的dataSource,而此时会不会获取到的是slave?

2. 事务隔离级别和传播特性会不会影响数据连接池死锁

一个线程在Service层Select数据会从数据库获取一个Connection,通常来讲,后续DB的操作在同一线线程会复用这个DB Connection,但是从Service进入Manager的事务后,Get Seq获取全局唯一标识,所以Get Seq一般都会开启新的事物从DB Pool里重新获取一个新连接进行操作,但是问题是如果两个事务关联的datasource是同一个,即DB Pool是同一个,那么如果DB Pool已经为空,是否会造成死锁?

为了减轻数据库的压力,一般会进行数据库的读写分离,实现方法一是通过分析sql语句是insert/select/update/delete中的哪一种,从而对应选择主从,二是通过拦截方法名称的方式来决定主从的,如:save*()、insert*() 形式的方法使用master库,select()开头的使用slave库。

通常在方法上标上自定义标签来选择主从。

或者通过拦截器动态选择主从。

读写动态库配置

DynamicDataSource:

定义动态数据源,实现通过集成Spring提供的AbstractRoutingDataSource,只需要实现determineCurrentLookupKey方法即可,由于DynamicDataSource是单例的,线程不安全的,所以采用ThreadLocal保证线程安全,由DynamicDataSourceHolder完成。

DynamicDataSourceHolder类:

动态设置数据源可以通过Spring AOP来实现,而AOP切面的方式也有很多种。

Spring AOP的原理:Spring AOP采用动态代理实现,在Spring容器中的bean会被代理对象代替,代理对象里加入了增强逻辑,当调用代理对象的方法时,目标对象的方法就会被拦截。

事务切面和读/写库选择切面

Java逻辑:

使用BeanNameAutoProxyCreator创建代理

Java逻辑:

Spring的事务处理为了与数据访问解耦,它提供了一套处理数据资源的机制,而这个机制采用ThreadLocal的方式。

事务管理器

Spring中通常通过@Transactional来声明使用事务。如果@Transactional不指定事务管理器,使用缺省。注意如果Spring容器中定义了两个事务管理器,@Transactional标注是不支持区分使用哪个事务管理器的,Spring 3.0之后的版本Transactional增加了个string类型的value属性来特殊指定加以区分。

同时进行XML配置

其中dataSource是在Spring配置文件中定义的数据源的对象实例。transaction-manager属性保存一个对在Spring配置文件中定义的事务管理器bean的引用,如果没有它,就会忽略@Transactional注释,导致代码不会使用任何事务。proxy-target-class控制是基于接口的还是基于类的代理被创建,如果属性值被设置为true,那么基于类的代理将起作用,如果属性值为false或者被省略,那么标准的JDK基于接口的代理将起作用。

注意@Transactional建议在具体的类(或类的方法)上使用,不要使用在类所要实现的任何接口上。

SQL四类隔离级别

事务的实现是基于数据库的存储引擎。不同的存储引擎对事务的支持程度不一样。Mysql中支持事务的存储引擎有InnoDB和NDB。InnoDB是mysql默认的存储引擎,默认的隔离级别是RR(Repeatable Read)。

事务的隔离性是通过锁实现,而事务的原子性、一致性和持久性则是通过事务日志实现。

(推荐阅读:数据库事务与MySQL事务总结 https://zhuanlan.zhihu.com/p/29166694)

Q1 在读写分离时会不会造成事务主从切换错误

一个线程在Serivcie时Select时选择的是从库,DynamicDataSourceHolder中ThreadLocal对应线程存储的是slave,然后调用Manager时进入事务,事务使用默认的transacatinManager关联的dataSource,而此时会不会获取到的是slave?

经验证不会,但这是因为在AOP设置动态织出的时候,都要清空DynamicDataSourceHolder的ThreadLocal,如此避免了数据库事务传播行为影响的主从切换错误。如果Selelct DB从库完成之后不清空ThreadLocal,那么ThreadLocal跟线程绑定就会传播到Transaction,造成事务操作从库异常。而清空ThreadLocal之后,Spring的事务拦截先于动态数据源的判断,所以事务会切换成主库,即使事务中再有查询从库的操作,也不会造成主库事务异常。

Q2 事务隔离级别和传播特性会不会影响数据连接池死锁

一个线程在Service层Select数据会从数据库获取一个Connection,通常来讲,后续DB的操作在同一线线程会复用这个DB Connection,但是从Service进入Manager的事务后,Get Seq获取全局唯一标识,所以Get Seq一般都会开启新的事物从DB Pool里重新获取一个新连接进行操作,但是问题是如果两个事务关联的datasource是同一个,即DB Pool是同一个,那么如果DB Pool已经为空,是否会造成死锁?

经验证会死锁,所以在实践过程中,如果有此实现,建议Get Seq不要使用与事务同一个连接池。或者采用事务隔离级别设置PROPAGATION_REQUIRES_NEW进行处理。最优的实践是宎把Get SeqId放到事务里处理。

总结

分析的不是很深,有很多地方还不是特别了解,欢迎吐槽相互学习,尤其是说错了的地方,一定请帮忙指正,以免误人子弟。

针对上面的技术我特意整理了一下,有很多技术不是靠几句话能讲清楚,所以干脆找朋友录制了一些视频,很多问题其实答案很简单,但是背后的思考和逻辑不简单,要做到知其然还要知其所以然。如果想学习Java工程化、高性能及分布式、深入浅出。微服务、Spring,MyBatis,Netty源码分析的朋友可以加我的Java进阶群:744642380,群里有阿里大牛直播讲解技术,以及Java大型互联网技术的视频免费分享给大家

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

看京东架构师如何解决,数据库读写分离与事务纠缠的坑 的相关文章

  • Spring Cloud Gateway + Spring安全资源服务器

    我真的不会把它放在这里 但我真的很困惑 我想实现以下目标 我在跑步 Java 14 Spring Cloud Gateway版本 Hoxton SR3 Spring Boot版本 2 2 5 RELEASE 现在我想将安全性集成到我的网关和
  • 关于Java中trim()方法的查询

    我之前提出了一个问题 但遭到了严厉的批评 所以我在这里再次提出 更简单 并重新措辞以吸引那些可能担心我之前提出问题的方式的人 背景 我正在解析一些 HTML 以获取信息 我将所有内容隔离在一系列行中 但我希望抓取的内容以及后面的一堆空格 为
  • 某些事务传播不适用于 Spring/Hibernate 4

    我正在将应用程序从 3 3 升级到 Hibernate 4 2 我们还使用 Spring 3 1 3 目前我们不能 不会更新 我的一些单元测试现在失败了 org hibernate HibernateException No Session
  • emacs 的最佳 java 工具 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Checkstyle 规则防止调用某些方法和构造函数

    是否可以使用 Checkstyle 来禁止使用某些使用系统相关默认值 区域设置 字符集等 的构造函数或方法 我更喜欢强制执行一项政策 程序员应该明确了解系统相关的值 所以我认为以下物品是危险的 all the constructors of
  • antisamy 解析器强制关闭标签

    我使用 Antisamy 来验证 HTML 我的政策允许 iframe 例如 YouTube 视频 问题是 如果标签为空 像这样 清洗后会是这样的 但它应该有正常的结束标签 这会破坏之后页面上的所有内容 我已经将指令设置为使用大部分 HTM
  • Swing 是否支持 Windows 7 风格的文件选择器?

    我刚刚添加了一个标准 打开文件 与我正在编写的一个小型桌面应用程序的对话 基于JFileChooserSwing 教程的入口 http download oracle com javase tutorial uiswing componen
  • 从壁纸中获取颜色? - 安卓

    如何找到当前壁纸的 平均 颜色并将该颜色设置为我的小部件上的布局 我正在尝试做的一个例子 这是 AccuWeather 上的设置 您可以使用WallpaperManager getWallpaperColors https develope
  • 在 JSON 转换为 CSV 期间保持 JSON 键的顺序

    我正在使用此处提供的 JSON 库http www json org java index html http www json org java index html为了将 json 字符串转换为 CSV 但我遇到的问题是 转换后键的顺序
  • 如果Jetty的密钥库中有多个证书,它如何选择?

    我们的系统中有一些代码用于自动将自签名证书生成到密钥库中 然后由 Jetty 使用 如果给定主机的密钥已经存在 那么什么也不会发生 但如果它不存在 我们会生成一个新密钥 如下所示 public void generateKey String
  • 如何设置 Eclipse 以停止发生异常的线路?

    如何设置 Eclipse 在发生异常时停止 我有一个 Eclipse 断点设置来在异常时中断 在下面的代码示例中 我遇到的问题是 Eclipse 尝试打开 Integer 源代码 有没有办法让调试器在我的代码示例中显示的位置中断 如果我向下
  • Java中的字符算术

    在玩的过程中 我遇到了一些对我来说似乎很奇怪的事情 以下不是有效的 Java 代码 char x A x x 1 possible loss of precision 因为其中一个操作数是整数 所以另一个操作数被转换为整数 结果无法分配给字
  • 如何使用 Java glob 模式搜索(区分大小写)文件?

    我正在检查获取路径匹配器 http docs oracle com javase 7 docs api java nio file FileSystem html getPathMatcher 28java lang String 29的方
  • 如何从java程序中编译.java文件[重复]

    这个问题在这里已经有答案了 可能的重复 从 Java 内部编译外部 java 文件 https stackoverflow com questions 10889186 compiling external java files from
  • GAE、JPA、XG 事务、实体组过多异常

    我知道 GAE 上的 XG 交易有 5 个实体组的限制 但我认为我在一项交易中仅使用 3 个组 商品 类别 商品类别 但仍然遇到此异常 引起原因 java lang IllegalArgumentException 在单个事务中对太多实体组
  • 遍历多行字符串

    我得到一些数据 def data some useless text n even more n finally interesting text 我怎样才能得到其中 有趣的部分 所以基本上所有行都不是以 开头的 Groovy 的一种选择是
  • 如何使用 Java 11 和 JavaFX 11 运行 ControlsFX 示例应用程序

    ControlFX 网站 http fxexperience com controlsfx says 如果您想使用 ControlsFX 示例应用程序 只需 下载 ControlsFX 版本并在上运行以下命令 命令提示符 请务必将 替换为实
  • Java:如何复制对象数组?

    现在 我有一个 Point 对象数组 我想制作一个COPY该数组的 我尝试过以下方法 1 Point temp mypointarray 2 Point temp Point mypointarray clone 3 Point temp
  • Spring Data 中 IQueryable 的等效项

    我习惯了 Net 和 LINQtoEntities 尤其是 IQueryable 部分 它允许在获取结果之前通过不同的函数传送请求 Spring数据中是否存在类似的东西 或者任何其他 java ORM 我希望能够做的基本示例 private
  • 使用 jar 外部的配置启动 .jar,但能够从任何当前目录执行此操作

    我一直在努力解决一个特定的问题 我在 jar 文件中有一个 Java 程序 并且在 jar 之外有一个 lib 目录和一个 config 目录 但与 jar 本身所在的目录位于同一目录中 我正在尝试参考config foo config从代

随机推荐

  • 数据挖掘学习之路二:数据预处理方法概述

    主要是将数据中缺失的数据补充完整 消除噪声数据 识别和删除离群点并解决不一致性 主要达到的目标是 将数据格式标准化 异常数据清除 错误纠正 重复数据清除 A 异常数据处理 分析异常数据 1 使用统计值进行判断 最大值 最小值 平均值等判断是
  • C++中的++i 与 i++详解

    一 区别 i 与 i 的主要区别有两个 1 i 返回原来的值 i 返回加1后的值 2 i 不能作为左值 而 i 可以 二 原理 毫无疑问大家都知道第一点 我们重点说下第二点 首先解释下什么是左值与右值 通俗地说 以赋值符号 为界 左边的就是
  • CUDA小白 - NPP(6) 图像处理 Geometry Transforms (2)

    cuda小白 原始API链接 NPP GPU架构近些年也有不少的变化 具体的可以参考别的博主的介绍 都比较详细 还有一些cuda中的专有名词的含义 可以参考 详解CUDA的Context Stream Warp SM SP Kernel B
  • npm包的发布和删除

    登录npm发布包 1 终端 输入npm login 可以登录npm账号 依次输入用户名 密码 密码盲打 邮箱 2 输入nrm use npm通过命令更改npm服务 需将npm切换为npm官方服务 不能使用taobao镜像 注 可以通过npm
  • 基于虚拟机的集群冗余简化

    为了实现高可用性 企业使用中间软件例如微软和 Veritas 的集群软件 把两台服务器绑定在一个热备环境 即使运行在服务器上的应用程序有集群 感知能力 万一主服务器遭遇硬件或软件错误 这样的安排仍然会导致非应 用程序当机 冗余能消除单点失败
  • 面经——嵌入式软件工程师ARM体系与架构相关

    参考 嵌入式软件工程师笔试面试指南 ARM体系与架构 作者 嵌入式与Linux那些事 发布时间 2021 04 28 15 22 06 网址 https blog csdn net qq 16933601 article details 1
  • Windows下配置nginx+php(wnmp)

    Windows下配置nginx php wnmp waynewuzhenbo 博客园 http www cnblogs com wuzhenbo p 3493518 html Windows下配置nginx php wnmp 第一部分 准备
  • GraphPad Prism 9 for mac/win 安装教程

    GraphPad Prism集生物统计 化学统计 以及科技绘图于一身 其中医学所能用到的绘图需要它几乎都能满足 Prism 现在被各种生物学家以及社会和物理科学家广泛使用 超过110个国家的超过20万名科学家依靠 Prism 来分析 绘制和
  • 删除节点后从新加入的错误

    ERR Node 172 168 63 202 7001 is not empty Either the nodealready knows other nodes check with CLUSTER NODES or contains
  • Qt中绘制直线

    绘制多条直线 直接上代码 绘制直线的部分 QPen pen Qt lightGray 1 pen setStyle Qt DashDotDotLine pen setWidth 1 painter setPen pen painter tr
  • JVM【八股文】

    JVM 八股文 JVM内存区域划分 程序计数器 栈 堆 方法区 一块大的区域 需要根据功能 来划分不同的小区域 JVM内存是从操作系统里申请来的 之后堆这部分区域进行了划分 1 程序计数器 内存中最小的区域 保存了下一条要执行指令的地址 指
  • Spring 如何使用注解装配Bean呢?

    转自 Spring 如何使用注解装配Bean呢 我们都知道在Spring中 可以使用xml可实现 Bean状态操作 但是如果有非常多的Bean时 就会出现大量的xml 这样就会导致配置文件非常的大 并且容易出错及难维护 Java 从JDK5
  • PHP取整,四舍五入取整、向上取整、向下取整、小数截取。

    PHP取整数函数常用的四种方法 1 直接取整 舍弃小数 保留整数 intval 2 四舍五入取整 round 3 向上取整 有小数就加1 ceil 4 向下取整 floor 一 intval 对变数转成整数型态 intval如果是字符型的会
  • 迭代器iterator

    能进行算术运算的迭代器只有随即访问迭代器 要求容器元素存储在连续内存空间里 vector string deque的迭代器是有加减法的 但是map set multimap multiset的迭代器是没有加减法的 list也不可以
  • minio老版本集成到k8s的yaml

    apiVersion apps v1 kind StatefulSet metadata name minio spec replicas 1 serviceName minio selector matchLabels name mini
  • Android WebView使用详解及注意事项

    未经本人授权 不得转载 否则必将维权到底 目前很多公司的 App 就只使用一个 WebView 作为整体框架 App 中的所有内容全部使用 HTML5 进行展示 这样只需要写一次 HTML5 代码 就可以在 Android 和 iOS 平台
  • Android textAppearance的属性设置及TextView属性详解

    http blog csdn net jaycee110905 article details 8762238 textAppearance的属性设置 android textAppearance android attr textAppe
  • html实现蜂窝菜单

    效果图 CSS样式 keyframes fade in mkmxd 1 0 filter blur 20px opacity 0 to filter none opacity 1 keyframes drop in mkmxd 1 0 tr
  • 【图片+代码】:GCC 链接过程中的【重定位】过程分析

    目录 示例代码 sub o 文件内容分析 段信息 符号表信息 main o 文件分析 段信息 符号表信息 绝对寻址 相对寻址 重定位表信息 可执行程序 main 段信息 符号表信息 绝对地址重定位 相对地址重定位 总结 别人的经验 我们的阶
  • 看京东架构师如何解决,数据库读写分离与事务纠缠的坑

    本篇文章讨论在数据库读写分离时使用事务的那些坑 1 在读写分离时会不会造成事务主从切换错误 一个线程在Serivcie时Select时选择的是从库 DynamicDataSourceHolder中ThreadLocal对应线程存储的是sla