Spring事务管理提供了灵活的方式来处理事务,包括事务的创建、提交、回滚以及事务的传播行为。 书接上回:Spring事务和事务传播机制(1) 2、Spring 中设置事务隔离级别 Spring 中事务隔离级别可以通过 @Transactional 中的 isolation 属性进行设置,具体操作如下图所示 该隔离级别因为可以读取到其他事务中未提交的数据,而未提交的数据可能会发生回滚,因此我们把该级别读取到的数据称之为脏数据,把这个问题称之为脏读 2、READ COMMITTED: 读已提交,也叫提交读,该隔离级别的事务能读取到已经提交事务的数据因此它不会有脏读问题 Spring 事务传播机制定义了多个包含了事务的方法,相互调用时,事务是如何在这些方法间进行传递的。 2、为什么需要事务传播机制? 嵌套事务和加入事务有什么区别 整个事务如果全部执行成功,二者的结果是⼀样的。 如果事务执行到一半失败了,那么加入事务整个事务会全部回滚;而嵌套事务会局部回滚,不会影响上一个方法中执行的结果
2PC github 在上一篇文章中我们介绍了本地事务,随着软件复杂度的上升,我们会需要一种可以在多个数据库之间完成事务(分布式事务)的方法,而这个方法也必须能够保证ACID。 于是就出现了2PC - Two phase commit protocol。事实上2PC不仅仅适用于多数据库事务场景下使用,也适用于所有支持2PC的参与方(Participants)。 缺点 根据上面的算法介绍可以看出2PC是一个阻塞协议: 如果两个事务针对同一个数据,那么后面的要等待前面完成,这是由于Cohort采用的是本地事务所决定的 Cohort在commit request phase 之后会阻塞,直到进入Coordinator告之Cohort进入commit phase 对于ACID的保证 2PC所保证的ACID和本地事务所提到的ACID不太一样——事实上对于所有分布式事务来说都不太一样 : A,正常情况下保证 C,在某个时间点,会出现A库和B库的数据违反一致性要求的情况 I,在某个时间点,A事务能够读到B事务部分提交的结果 D,和本地事务一样,只要commit则数据被持久 XA XA是一个针对分布式事务的
场景:你的业务一次操作需要同时更新多个资源,比如:两个不同的MySQL库(你现在问的场景)数据库+消息队列数据库+缓存等如果不用分布式事务,就可能出现:A库更新成功,B库更新失败→数据不一致2PC要解决的就是 二、2PC会带来哪些问题?1.性能开销大一次事务要走两个阶段,网络往返多、日志写入多。prepare阶段会长时间持有锁到commit完成,吞吐量下降,冲突增多。 2.锁时间长,容易造成阻塞在prepare之后到最终commit/rollback之前,相关行/页/表都被锁住。协调器慢、网络抖动、参与者负载高→这些锁就会被持有更久,其他事务被阻塞,甚至导致雪崩。 6.运维与排错困难出现「悬挂事务」「prepare卡住」「XA事务残留」等问题时,排查和处理都比较重。需要看协调器日志、各库的XA状态,甚至手工XARECOVER/XACOMMIT/ROLLBACK。 所以很多系统宁可用「本地事务+Outbox+CDC/消息」做最终一致性,也会慎用XA级别的2PC。
Redis事务没有事务隔离的级别。 但是Redis事务的本质是:将一组操作放入队列(先进先出)中,批量执行。 关系型数据库的事务是:将事务操作(DML)语句写入日志。 事务相关的命令 Multi:开启事务 Exec:执行事务 Discard:终止事务 image.png 说明:Exec之前的事务操作可以被discard终止 但是一旦exec 本次事务就会执行! Redis 如何实现事务呢? 开启一个队列 让命令进入队列 执行事务 # 1 开启事务 multi # 2 输入命令 set k1 v1 set k2 v2 get k2 set k2 v3 get k2 # 3 执行/放弃事务 watch 需要锁Key名 # 线程1 操作:开启事务,并设置money为80 但不执行事务 multi set money 80 或者 decrby money 20 # 线程2 操作:读取money
1.怎么使用事务消息实现分布式事务消息队列中的“事务”,主要解决的是消息生产者和消息消费者的数据一致性问题应用场景:订单系统下订单后,需要在购物车系统清空购物车事务消息适用的场景主要是那些需要异步更新数据 方案:1.TCC 2PC 3PC Saga(强一致性,并发量不发的情况下使用,比如下订单和使用优惠券)2.可以使用本地消息表实现最终一致性(可以短时间接受不一致,前提是:异步执行的部分不依赖资源)3.使用支持事务的消息中间件 RocketMQ Kafka(本地消息表思想的一种实现,使用起来更简单)具体以方案3事务消息实现分布式消息为例:图片1.开启事务2.发送半消息3.成功后执行本地事务,创建订单4.本地事务执行成功,则提交事务 ;本地事务执行失败,则回滚事务细心的同学发现步骤4:如果本地事务执行成功,提交事务的时候,请求失败了,怎么办? RocketMQ 会自动根据事务反查的结果提交或者回滚事务消息。图片2.怎么保证消息顺序消费?
2 改造前 (性能数据没有太大参考意义,只用于前后对比) 16C小规格测试机128并发压测,PG参数全部异步写,瓶颈来到事务ID生成 128并发压测只写120秒XidGen锁每秒的出现数量:均值在60左右 = 80589 -- 参数 fsync = off synchronous_commit = off autovacuum = off create table testbl1(c1 int, c2 3.1 改造方案一 【本地进程】拿事务ID从一次拿一个变成一次拿N个,其他不变。 关键改造点: GetNewTransactionId:预存本地N个事务ID,取的时候先取本地,再去共享的。 GetSnapshotData:要求事务ID必须严格递增,这里可能会有空洞触发assert。 3.2 改造方案二(较复杂不做测试) 拿事务ID由每个进程自己拿,变成由一个进程统一分配。
——恩格斯 官方demo: https://github.com/spring-projects/spring-data-examples/blob/main/r2dbc/example/src/main /java/example/springdata/r2dbc/basics/TransactionalService.java /* * Copyright 2019-2021 the original IllegalStateException(); } else { return it; } }); } } 可以看到是支持Transactional的 当然我们可以手动回滚事务 ,配置: import io.r2dbc.spi.ConnectionFactory; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.r2dbc.connection.R2dbcTransactionManager
React 15.4.2 ,以下是本系列其它文章的传送门: React 源码深度解读(一):首次 DOM 元素渲染 - Part 1 React 源码深度解读(二):首次 DOM 元素渲染 - Part 2 源码深度解读(三):首次 DOM 元素渲染 - Part 3 React 源码深度解读(四):首次自定义组件渲染 - Part 1 React 源码深度解读(五):首次自定义组件渲染 - Part 2 React 源码深度解读(六):依赖注入 React 源码深度解读(七):事务 - Part 1 React 源码深度解读(八):事务 - Part 2 React 源码深度解读(九):单个元素更新 React
,也可能存在不同服务器的库里,所以就出现了分布式 事务,分布式的解决方案有多种,例如2PC,3PC,TCC等,今天主要来说一下2PC事务的思想。 2PC阶段解释 2PC指的是两阶段提交,整个事务流程分为两个阶段,分别为Prepare阶段和Commit阶段,Prepare为预提交阶段,它不会提交事务,Commit阶段才是真正的提交 事务的阶段,2PC 2PC流程 协调者向参与者发送Prepare消息 协调者向参与者发送Prepare消息,参与者执行完本地事务后返回协调者一个状态,表明自己是否能够执行,并将执行的事务保存起来,并没有提交。 思考 我们从2PC的整个流程中可以看出其实会有一些问题。 效率问题 当某个事务在执行的过程中,资源是会被锁住的,那么其他事务就会被阻塞,直到当前事务完成后 才轮到下一个事务执行,这在高并发的情况下显然不行,如果事务不耗时还好说,如果事务很耗时,那么就无法忍受了
目录 1、什么是事务? 2、介绍下数据库事务? 3、并发事务会带来什么问题? 3.1、不可重复读和幻读有什么区别? 4、数据库隔离级别有哪几种? 5、MySQL默认使用隔离级别是啥? 6、如何控制并发事务? 6.1、锁 6.2、MVCC 1、什么是事务? 事务指的是逻辑上的一组操作,这组操作要么都执行,要么都不执行。 这显然都是不允许的,因此事务会把这两个操作看作一个逻辑的整体,这组整体包含的状态必须是一致的。 2、介绍下数据库事务? 一个事务所作的修改在最终提交前,对其他事务是不可见的。如前面第2条SQL从老板账户扣钱500元的时候,如果事务还没提交,此时另一个线程查询老板的账户,其看到的账户余额是没有减去500的。 此时两个事务都对这个数据进行了修改,那么其中一个事务的修改就可能被另一个事务的修改所覆盖,导致另一个事务的修改丢失。
db2锁 ⑴ 引言 在关系型数据库(BD2,Oracle,Sybase,Informix和Sql Server)最小的恢复和交易单位为一个事务,事务具有ACID(原子性,一致性,隔离性,永久性)特征。 ⑵ DB2多力度封锁机制 锁的对象 DB2支持对表空间、表、行和索引加锁(大型机上的数据库还可以支持对数据页加锁)来保证数据库的并发完整性。 DB2表锁的模式 表一:DB2数据库表锁的模式 下面对几种表锁的模式进一步加以阐述: IS、IX、SIX方式用于表一级并需要行锁配合,他们可以阻止其他应用程序对该表加上排它锁。 DB2行锁的模式 表二:DB2数据库行锁的模式 2.2.3 DB2锁的兼容性 表三:DB2数据库表锁的相容矩阵 表四:DB2数据库行锁的相容矩阵 下表是本篇文章的作者总结了DB2中各SQL语句产生表锁的情况 (假设缺省的隔离级别为CS): DB2锁的升级 每个锁在内存中都需要一定的内存空间,为了减少锁需要的内存开销,DB2提供了锁升级的功能。
在分析了qs的大致源码后golang源码分析:dtm分布式事务(1),我们分析下dtm-example的源码结构,每个例子都是类似的。 如果没有知名具体实例参数,列出参数列表 func hintExit(msg string) { _, cmd := range examples.Commands 然后是将数据库里未提交的事务回滚掉
SAP QM 事务代码QAC2的BUG? SAP QM模块里的事务代码QAC2可以用于将检验批上绑定的质检库存做转库动作。笔者近期在项目上发现该事务代码的一个令人费解的BUG,写下本文予以记录。 我们可以执行事务代码QAC2对该检验批进行处理, 将存地点改为0001, 回车, 业务人员发现手工输入错误,正确的存储地点应该是1000,所以他又将存储地点改为1000。 也就是说如果要把该检验批里的库存转入1000存储地点,则只能退出当前的QAC2事务代码的界面,重新执行QAC2,把目的地存储地改成1000,然后才能成功的保存。 也即是说QAC2事务代码中,如果业务人员手工输入了错误的存储地点,回车后就不能再次输入正确的存储地点以实现对QI库存做转库过账业务了。 而事务代码QAC2里却不能这么玩,笔者认为这是SAP中事务代码QAC2的BUG。 聪明的你,是否认同呢? -完- 写于2022-2-21.
摘要 通过创建逻辑会话,现在可以跟踪单操作事务或者包含多个操作的事务在整个系统中资源消耗情况。这样就可以简单地,精确地取消事务中的操作以及采取分布式的模式进行垃圾回收。 逻辑会话和事务 通过使用逻辑会话ID标记所有操作和使用的资源,现在可以更轻松地管理MongoDB中的长期活跃和广泛分布的数据库操作了。 确保一个事务在一个会话中运行,那么无论事务是成功提交还是被中止,使用逻辑会话可以保证存储和清理该事务所占用的资源。
SAP顾问初阶之事务代码SMQ2事务代码SMQ2用于查询通过RFC与外部系统接口的RFC的日志信息。 执行事务代码SMQ2,进入如下界面,系统自动填入client代码比如010,保持Queue Name字段值为*,点击执行,进入如下界面,界面显示qRFC Monitor的结果,如上图。
SAP QM 事务代码QA16初探(2)近日研习SAP QM模块的事务代码QA16, 发现了一个怪异的现象。是故写下这篇文字,算是一个备忘录吧。 1, 执行事务代码QA33,显示工厂代码NM01下的09类型的检验批,共计6个检验批,三个被取消的检验批,三个正常检验批(尚未录入检验结果)。 2, 执行事务代码QA16,观察SAP的行为。输入相关参数后,执行,得到如下结果,三个被取消的检验批被显示出来,而另外三个没有录入检验结果的正常检验批却未能显示出来! 3, 事务代码QA16的标题是:Collective Usage Decision for OK Lots。 被取消的检验批能算是OK Lots? 而正常未录入的检验批却不能被算是OK Lots? QA16这个事务代码,有其相应的后台逻辑。这些后台逻辑,可能会与我们SAP咨询顾问的常规认知有些不同。
死锁与活锁 和操作系统一样,封锁的方法可能引起活锁和死锁 活锁 如果事务T1封锁数据D,事务T2又请求封锁数据D,于是T2等待。 事务T3也请求封锁D,当T1释放D上的封锁之后系统首先批准了T3的请求,T2又等待,然后T4又请求封锁D。。。 T2永远等待 避免活锁的简单方法就是采用先来先服务的策略 死锁 事务T1封锁了数据D1,T2封锁了数据D2,然后T1又请求封锁D2,因为T2已封锁了D1,于是T1等待T2释放D2,接着T2请求封锁D1, T1、T2相互等待,产生死锁。 死锁的预防: 1)一次封锁法:一次封锁法要求事务必须一次将所有要使用的数据全部加锁。 2)在释放一个封锁之后,事务不在申请和获得其他封锁。 也就是说事务分为两个阶段。第一个阶段是获得封锁,也称为扩展阶段。在这个阶段,事务可以申请获得任何数据项任何类型的锁,但是不能释放任何锁。
二、事务提交过程概览 1.二阶段对应图 raincat是一个二阶段分布式事务处理框架,在事务的提交过程中,对应的二阶段如下: 第一阶段(准备阶段) 记录事务信息,准备提交。 2.事务提交过程概览 整个事务的提交过程,如下: (1)切面开始,拦截 @TxTransaction 注解 (2)协调者为发起者创建事务组信息(入Redis) (3)发起者开启本地事务,并执行业务方法 线程B中,开启本地事务,让协调者将参与者的事务加入到(2)中的事务组中,然后执行本地业务方法。 以下异步执行 (5)唤醒线程A,参与者业务方法执行完毕。(3)中得到返回结果。 (7)协调者收到请求后,通知发起者提交事务。协调者更新事务组状态为提交,并判断是否能提交。然后通知参与者提交事务,接着通知其他TM提交事务。 三、事务提交过程时序图 下图主要是以事务发起者的角度分析整个事务提交流程
本文继续介绍事务划分在当前JavaEE技术体系下基于EJB的实现方案。虽然EJB算是JavaEE的亲儿子,但是它的境遇却不怎么好,主要是被EJB 2.x给坑过的开发人员都对他失去了兴趣。 事务划分概要 Resource-local事务类型 在上文中我们已经知道Resource-local事务类型实际上就是直接建立在JDBC标准的中的DataSource接口之上的一种事务类型,它直接建立在底层数据库所支持的事务之上 那么有事务的创建就有事务的提交(回滚),有事务的挂起就有事务的唤起(resume)。 不像CMT那样通常以业务方法的开始和结束作为事务的起点和终点。如果只开始了一个事务,而忘记关闭它,那么会导致异常的发生,同时该事务也会被容器回滚。 而且,BMT类型的事务无法使用从外部进入的事务。 然而一个线程是可以关联多个事务的,否则事务的挂起和唤起从何谈起。 显而易见,begin()方法是事务的唯一出发点。
接上期,MongoDB 的事务操作已经操作了,但细节和参数并没有弄清楚,通过mongodb 的事务操作主要分为以下几个部分 1 Session.startTransaction 2 Session.commitTransaction 事务中多个操作,其中之一失败,则事务整体失败,则在失败事务之前的操作全部丢弃。这里暂且认为MONGODB 的事务是 READ COMMITED 的方式对我们呈现的。 游标如果是在事务内发生的,则只能在事务内部调用,同理事务内部不能调用外部的游标。 事务的操作中,如果事务中的一个单独的操作失败了,是不会在进行重试,在事务commit 的阶段提交如果失败了,MONGODB 是会进行重试的。 那么一个完整的事务的提交并且包含重试和报错的程序怎么来操作 下面是一些操作步骤, 1 登陆mongoshell 通过mongosh 登陆 (不知道什么是mongosh 可以去官网看一下) 2 两个