关于事务:事务原理了解一下

1、聊聊事务原理一句话来说,要么胜利,要么失败,不能有两头态 1.1、回顾一下ACIDAtomic:原子性,就是一堆SQL,要么一起胜利,要么都别执行,不容许某个SQL胜利了,某个SQL失败了,这就是扯淡么Consistency:一致性,这个是针对数据一致性来说的,就是一组SQL执行之前,数据必须是精确的,执行之后,数据也必须是精确的。别搞了半天,执行完了SQL,后果SQL对应的数据批改没给你执行,这不是坑爹么Isolation:隔离性,这个就是说多个事务在跑的时候不能相互烦扰,别事务A操作个数据,弄到一半儿还没弄好呢,后果事务B来改了这个数据,导致事务A的操作出错了,那不就搞笑了么Durability:持久性,事务胜利了,就必须永恒对数据的批改是无效的,别过了一会儿数据本人没了,不见了,那就好玩儿了1.2、陈词滥调的事务隔离级别读未提交(Read Uncommitted):这个很坑爹,就是说某个事务还没提交的时候,批改的数据,就让别的事务给读到了,这就恶心了,很容易导致出错的。这个也叫做脏读读已提交(Read Committed)又叫做不可反复读:这个比下面那个略微好一点,然而一样比拟难堪,就是说事务A在跑的时候, 先查问了一个数据是值1,而后过了段时间,事务B把那个数据给批改了一下还提交了,此时事务A再次查问这个数据就成了值2了,这是读了人家事务提交的数据啊,所以是读已提交。这个也叫做不可反复读,就是所谓的一个事务内对一个数据两次读,可能会读到不一样的值可反复读(Read Repeatable):这个就是比下面那个再好点儿,就是说事务A在执行过程中,对某个数据的值,无论读多少次都是值1;哪怕这个过程中事务B批改了数据的值还提交了,然而事务A读到的还是本人事务开始时这个数据的值串行化:幻读,不可反复读和可反复读都是针对两个事务同时对某条数据在批改,然而幻读针对的是插入,比方某个事务把所有行的某个字段都批改为了2,后果另外一个事务插入了一条数据,那个字段的值是1,而后就难堪了。第一个事务会忽然发现多进去一条数据,那个数据的字段是1。如果要解决幻读,就须要应用串行化级别的隔离级别,所有事务都串行起来,不容许多个事务并行操作2、MySQL的事务隔离级别分析一下2.1、InnoDB存储引擎架构设计 2.2、MySQL是怎么实现RR事务隔离的2.2.1、Redo Log日志理解一下 2.2.2、MVC Undo Log日志链条事务A,插入了一条数据接着有一个事务B跑来批改了一下这条数据接着假如事务C又来批改了一下这个值为C2.2.3、 MySQL RR readview + undo log日志链首先假如有一条数据是事务id=50的一个事务插入,之后有事务A和事务B同时在运行事务A发动一个查问,他就是第一次查问就会生成一个ReadView,此时ReadView里的creator_trx_id是60,min_trx_id是60,max_trx_id=71,m_ids=[60,70]这个时候事务A基于这个ReadView去查问这条数据,会发现这条数据的trx_id=50,是小于ReadView里的min_trx_id的,阐明他发动查问之前,早就有事务插入这条数据了还提交了所以此时能够查到这条原始数据接着事务B此时更新了这条数据的值为B,此时会批改trx_id=70,同时生成一个undo log,而且此时事务B还提交了,也就是说事务B曾经完结了这个时候有一个问题,ReadView中的m_ids此时还会是60和70吗?那是必然的,因为ReadView一旦生成就不会扭转了,这个时候尽管事务B曾经完结了,然而事务A的ReadView里,还是会有60和70两个事务id,意思就是说,你在事务A开启的时候,事务B过后是在运行的那好,接着此时事务A去查问这条数据的值,他会诧异的发现此时数据的trx_id是70了,70一方面是在ReadView的min_trx_id和max_trx_id的范畴区间的,同时还在m_ids列表中阐明起码是事务A开启查问的时候,id=70的这个事务B还是在运行的,而后由这个事务B更新了这条数据,此时事务A是不能查问到事务B的这个值的,因而这个时候只能顺着指针往历史版本链条下来找接着事务顺着指针找到上面一条数据,trx_id为50,是小于ReadView的min_trx_id的,阐明在他开启查找之前,就曾经提交这个事务了,所以事务A是能够查问到这个值的,此时事务A查到的是原始值你事务A屡次读同一个数据,每次读到的都是一样的值,除非是他本人批改了值,否则读到的都是一样的值,不论别的事务如何批改数据,事务A的ReadView始终是不变的,他基于这个ReadView始终看到的值是一样的接着此时事务A再次查问,此时发现符合条件有2条数据,一条是原始值的那个数据,一条是事务C插入的那条数据,然而事务C插入的那条数据的trx_id是80,这个80是大于本人的ReadView的max_trx_id的,阐明是本人发动查问之后,这个事务才启动的,所以此时这条数据是不能查问的,所以MySQL RR防止了幻读3、XA标准理解一下X/Open的组织定义了分布式事务的模型,这外面有几个角色,就是AP(Application,应用程序),TM(Transaction Manager,事务管理器),RM(Resource Manager,资源管理器),CRM(Communication Resource Manager,通信资源管理器)TM的话就是一个在零碎里嵌入的一个专门治理横跨多个数据库的事务的一个组件,RM的话说白了就是数据库(比方MySQL),CRM能够是消息中间件(然而也能够不必这个货色) 那么XA是啥呢?说白了,就是定义好的那个TM与RM之间的接口标准,就是治理分布式事务的那个组件跟各个数据库之间通信的一个接口 这个XA仅仅是个标准,具体的实现是数据库产商来提供的,比如说MySQL就会提供XA标准的接口函数和类库实现 JTA(Java Transaction API),是J2EE的编程接口标准,它是XA协定的JAVA实现,例如Atomikos, bitronix都提供了jar包形式的JTA实现框架。这样咱们就可能在Tomcat或者Jetty之类的服务器上运行应用JTA实现事务的利用零碎,个别是单机跨多库状况下,然而在微服务的明天,个别都是一个服务一个库,个别都不会这么干了 3.1、2PC是啥?X/Open组织定义的一套分布式事务的模型,还是比拟虚的,还没方法落地,而且XA接口标准也是一个比拟务实的一个货色,还是没法落地的2PC说白了就是基于XA标准搞的一套分布式事务的实践,也能够叫做一套标准,或者是协定 毛病:1、同步阻塞:在阶段一里执行prepare操作会占用资源,始终到整个分布式事务实现,才会开释资源,这个过程中,如果有其他人要拜访这个资源,就会被阻塞住2、单点故障:TM是个单点,一旦挂掉就完蛋了3、事务状态失落:即便把TM做成一个双机热备的,一个TM挂了主动选举其余的TM进去,然而如果TM挂掉的同时,接管到commit音讯的某个库也挂了,此时即便从新选举了其余的TM,压根儿不晓得这个分布式事务以后的状态,因为不晓得哪个库接管过commit音讯,那个接管过commit音讯的库也挂了4、脑裂问题:在阶段二中,如果产生了脑裂问题,那么就会导致某些数据库没有接管到commit音讯,那就完蛋了,有些库收到了commit音讯,后果有些库没有收到,这咋整呢,那必定完蛋了 3.1、3PC是啥?如果人家TM在DoCommit阶段发送了abort音讯给各个库,后果因为脑裂问题,某个库没接管到abort音讯,本人还执行了commit操作,不是也不对么 4、TCC是个什么原理(柔性事务)try、confirm和cancel 4.1、容许空回滚事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会呈现因为丢包而导致的网络超时,此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,而 Cancel 操作调用未呈现超时TCC 服务在未收到 Try 申请的状况下收到 Cancel 申请,这种场景被称为空回滚;空回滚在生产环境经常出现,用户在实现TCC服务时,应容许容许空回滚的执行,即收到空回滚时返回胜利 4.2、防悬挂管制事务协调器在调用 TCC 服务的一阶段 Try 操作时,可能会呈现因网络拥挤而导致的超时,此时事务管理器会触发二阶段回滚,调用 TCC 服务的 Cancel 操作,Cancel 调用未超时;在此之后,拥挤在网络上的一阶段 Try 数据包被 TCC 服务收到,呈现了二阶段 Cancel 申请比一阶段 Try 申请先执行的状况,此 TCC 服务在执行完到的 Try 之后,将永远不会再收到二阶段的 Confirm 或者 Cancel ,造成 TCC 服务悬挂。用户在实现 TCC 服务时,要容许空回滚,然而要拒绝执行空回滚之后 Try 申请,要避免出现悬挂 ...

April 2, 2023 · 1 min · jiezi

关于事务:mysql-事务隔离级别介绍

一、论断-MySQL5.6和MySQL 8 的默认隔离级别为 Repeatable Read(可反复读)在 Repeatable Read 隔离级别下,事务开始时会获取一致性快照,并在事务完结之前放弃这个快照。这意味着在事务执行期间,读取的所有数据都来自于这个快照,而不会受到其余事务的批改影响。因而,在这个隔离级别下,即便其余事务批改了数据,以后事务也不会看到这些批改,直到以后事务提交。 须要留神的是,MySQL 的隔离级别能够通过设置来更改,并且不同的存储引擎可能有不同的默认隔离级别。因而,在理论利用中,须要依据具体的需要来抉择适合的隔离级别。 二、MySQL的四种隔离级别存在的问题1、读未提交(Read Uncommitted):最低级别的隔离级别,容许一个事务读取另一个事务未提交的数据,可能导致脏读、不可反复读和幻读等问题。 2、读已提交(Read Committed):保障一个事务读取到的数据是另一个事务曾经提交的数据,解决了脏读的问题,但可能导致不可反复读和幻读等问题。 3、可反复读(Repeatable Read):保障一个事务读取到的数据不会被其余事务批改,解决了脏读和不可反复读的问题,但可能导致幻读等问题。 4、串行化(Serializable):最高级别的隔离级别,齐全解决了脏读、不可反复读和幻读等问题,然而会导致并发性能升高。 须要留神的是,不同的隔离级别解决的问题和带来的问题是绝对的,并且不同的利用场景须要不同的隔离级别来保证数据的一致性和并发性能。因而,在抉择隔离级别时须要依据具体的需要进行衡量和抉择。 三、脏读,幻读,不可反复读含意解释1、脏读(Dirty Read)指的是一个事务读取了另一个事务还未提交的数据。如果另一个事务最终回滚了,则第一个事务读取的数据是有效的。这种读取未提交的数据可能导致意外的后果,因为这些数据可能会随时被回滚或批改。 2、幻读(Phantom Read)是指在同一事务中执行雷同的查问,但返回了不同的后果行数。这通常产生在并发环境中,其中一个事务在读取数据时另一个事务插入了一些新的数据行或删除了一些已存在的数据行。 3、不可反复读(Non-repeatable Read)指的是在同一事务中屡次执行雷同的查问,但返回不同的后果。这可能是因为其余事务批改了数据或者在同一事务中本人批改了数据导致的。这种状况下,数据在事务执行期间产生了扭转,所以事务之间可能会发生冲突。 这些问题可能会影响数据库的一致性和可靠性,因而须要采取相应的措施来解决这些问题,如应用锁机制、事务隔离级别等。 四、隔离级别选型参考抉择适当的数据库隔离级别须要思考多个因素,例如应用程序的要求、并发性需求、性能需求、数据完整性需要等等。以下是一些通用的思考因素: 1、并发性需求:如果应用程序须要反对高并发性,那么能够思考抉择较低的隔离级别,例如读未提交或读已提交。这些隔离级别能够缩小锁定抵触,从而进步并发性。然而,这也会减少一些数据不统一的可能性。 2、数据完整性需要:如果应用程序须要保证数据的完整性,例如防止脏读(Dirty Read)和不可反复读(Non-repeatable Read)等问题,那么能够思考抉择较高的隔离级别,例如可反复读或可串行化。 3、应用程序要求:不同的应用程序对数据一致性的要求也不同。例如,某些应用程序可能更重视数据的实时性,而对数据的一致性要求较低,那么能够抉择较低的隔离级别。然而,对于一些须要保证数据一致性的应用程序,须要抉择更高的隔离级别。

March 5, 2023 · 1 min · jiezi

关于事务:事务的隔离级别

事务的隔离级别事务的四大个性别离是:原子性、一致性、隔离性、持久性 幻读和不可反复读都是在同一个事务中屡次读取了其余事务曾经提交的事务的数据导致每次读取的数据不统一,所不同的是不可反复读读取的是同一条数据,而幻读针对的是一批数据整体的统计(比方数据的个数) 以MYSQL数据库来剖析四种隔离级别 第一种隔离级别:Read uncommitted(读未提交)如果一个事务曾经开始写数据,则另外一个事务不容许同时进行写操作,但容许其余事务读此行数据,该隔离级别能够通过“排他写锁”,然而不排挤读线程实现。这样就防止了更新失落,却可能呈现脏读,也就是说事务B读取到了事务A未提交的数据 解决了更新失落,但还是可能会呈现脏读 第二种隔离级别:Read committed(读提交)如果是一个读事务(线程),则容许其余事务读写,如果是写事务将会禁止其余事务拜访该行数据,该隔离级别防止了脏读,然而可能呈现不可反复读。事务A当时读取了数据,事务B紧接着更新了数据,并提交了事务,而事务A再次读取该数据时,数据曾经产生了扭转。 解决了更新失落和脏读问题 第三种隔离级别:Repeatable read(可反复读取)可反复读取是指在一个事务内,屡次读同一个数据,在这个事务还没完结时,其余事务不能拜访该数据(包含了读写),这样就能够在同一个事务内两次读到的数据是一样的,因而称为是可反复读隔离级别,读取数据的事务将会禁止写事务(但容许读事务),写事务则禁止任何其余事务(包含了读写),这样防止了不可反复读和脏读,然而有时可能会呈现幻读。(读取数据的事务)能够通过“共享读镜”和“排他写锁”实现。 解决了更新失落、脏读、不可反复读、然而还会呈现幻读 第四种隔离级别:Serializable(可序化)提供严格的事务隔离,它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行,如果仅仅通过“行级锁”是无奈实现序列化的,必须通过其余机制保障新插入的数据不会被执行查问操作的事务拜访到。序列化是最高的事务隔离级别,同时代价也是最高的,性能很低,个别很少应用,在该级别下,事务程序执行,不仅能够防止脏读、不可反复读,还防止了幻读 解决了更新失落、脏读、不可反复读、幻读(虚读) 以上四种隔离级别最高的是Serializable级别,最低的是Read uncommitted级别,当然级别越高,执行效率就越低,像Serializeble这样的级别,就是以锁表的形式(相似于Java多线程中的锁)使得其余线程只能在锁外期待,所以平时选用何种隔离级别应该依据理论状况来,在MYSQL数据库中默认的隔离级别是Repeatable read(可反复读)。 在MYSQL数据库中,反对下面四种隔离级别,默认的为Repeatable read(可反复读);而在Oracle数据库中,只反对Serializeble(串行化)级别和Read committed(读已提交)这两种级别,其中默认的为Read committed级别 在MYSQL数据库中查看以后事务的隔离级别 SELECT @@tx_isolation;在MYSQL数据库中设置事务的隔离级别: 记住:设置数据库的隔离级别肯定要是在开启事务之前: 如果是应用JDBC对数据库的事务设置隔离级别的话,也应该是在调用Connecton对象的setAutoCommit(false)办法之前,调用Connection对象的setTransactionIsolation(level)即可设置以后连贯的隔离级别,至于参数level,能够应用Connection对象的字段: 在JDBC中设置隔离级别的局部代码: 隔离级别的设置只对以后连贯无效,对于应用MYSQL命令窗口而言,一个窗口就相当于一个连贯,以后窗口设置的隔离级别只对以后窗口中的事务无效,对于JDBC操作数据库来说,一个Connection对象相当与一个连贯,而对于Connection对象设置的隔离级别只对该Connection对象无效,与其余连贯Connection对象无关

November 23, 2022 · 1 min · jiezi

关于事务:真正理解可重复读事务隔离级别

原创:打码日记(微信公众号ID:codelogs),欢送分享,转载请保留出处。事务简介SQL 规范定义了四种隔离级别,这四种隔离级别别离是: 读未提交(READ UNCOMMITTED):在这种隔离级别下,可能会呈现脏读、不可反复读、幻读问题。 读提交 (READ COMMITTED):解决脏读问题。 可反复读 (REPEATABLE READ):解决脏读、不可反复读问题。 串行化 (SERIALIZABLE):解决脏读、不可反复读、幻读问题。这里不具体解释脏读、不可反复读、幻读问题这些景象了,介绍事务的文章或书根本都会说得很分明,但请留神,这些都是事务并发运行时可能产生的景象,而不能了解为数据库的bug! 但我在工作多年后再想到这些常识时,对可反复读行为产生十分大的疑难,如下: 程序员为什么不把第一次读的数据保留在内存中,第二次重复使用不行吗?为啥要数据库保障两次读出的数据是雷同的(即可反复读),并且读两次数据库会节约更多数据库资源而升高性能。另外,每次读出最新的数据有啥不好?读个历史数据有啥用?既然如此,可反复读到底有什么用? 举个例子咱们能够考查上面这样的场景,有个金融产品有一个性能,须要查找那些账号余额与账号交易流水对不上的用户,咱们叫到账工作吧,而且要在对账工作运行时,用户交易失常不中断。 比方某账号余额100元,该账号有两笔交易记录(+200, -100),这样这个账号就对账失常,但如果程序查问出账号余额100元后,这时用户又转出100元,咱们再去查问交易记录时,在不同事务隔离级别下会查到不同的后果,如下: 提交读可反复读备注 开始时余额100,交易记录(+200, -100)查问到余额100元查问到余额100元 另一事务收入100元,余额缩小为0,并提交查问到交易记录(+200, -100, -100)查问到交易记录(+200, -100) 对账失败对账胜利 可见,在提交读场景下,对账失败了,而可反复读场景下对账胜利了,而实际上这个账号的余额与交易记录始终是对齐的。我在MySQL5.7亲自验证,后果的确如此。 所以可反复读具体作用是什么呢? 所以可反复读具体作用是什么呢? 所以可反复读具体作用是什么呢?它实质作用是保障在开启事务后,对数据库所有表数据的查问,查问到的都是雷同的版本,就是开启事务那一刻的版本(在mysql中为第一次查问那一刻的版本),而不论它是查问的一个表,还是不同的表,所以可反复读事务级别解决的并不是外表上的不可反复读景象。 可反复读也常常用在数据库备份过程中,因为数据库备份时数据还有可能在一直批改,咱们必定心愿备份整个数据库开始时的那个版本,而不心愿备份的数据有些是之前那个时刻版本的,有些则是之后那个工夫版本的。 这个例子也阐明了另一个问题,即什么时候须要应用事务,刚写代码时咱们常常被告知所有写操作要放到一个事务中,实际上,一些非凡场景,多个读操作也要放到一个事务中。 换角度了解事务咱们能够不从赃读,不可反复读,幻读这些景象看事务隔离级别,而是从读一致性上来了解,如下: 未提交读,不解决任何读一致性问题,只保障了事务的写一致性(又称原子性),事务提交后,要么都批改胜利,要么都不胜利。提交读,保障其它并发事务的批改要么全可见,要么全不可见,能够了解为"写一致性读",留神断句!"写一致性"、"读",这是最罕用的事务隔离级别,能够保障业务数据含意的一致性。 比方用户下单场景,开事务先后写了order主表订单数据与order_item子表订单中商品数据,如果在两个写两头,有一个未提交读的事务,去读取order与order_item,就会发现只读到了order而没有读到order_item,这给用户看到了,那肯定会吓一跳的,我交钱了后果买了一个空单!尽管用户刷新一下又能够看到残缺数据。 但如果应用提交读事务隔离级别就不会有这个问题,用户要么查不到任何数据,要么查到残缺数据,这也从侧面阐明了逻辑上有关联的数据批改,肯定要开事务来操作。可反复读,保障事务开启或第一次查问那一刻,前面所有对整个数据库所有表的读都是读那一刻的版本,当然包含反复读同一张表,也能够了解为"统一版本读"。串行化,一般来说解决的是并发上的逻辑谬误,因为此级别逻辑上能够认为所有事务都是串行执行的(尽管数据库实际上可能会并发执行)。 比方两个事务先判断数据有没有,没有则插入数据的场景,并发状况下两个事务同时查问,发现没有数据后插入数据,后果插入了两条数据,而应用串行化隔离级别就没有这个问题,这在并发编程中叫竞态条件,所以串行化解决了读写的竞态条件问题。 当然,这个问题也能够通过增加惟一索引,或应用内部显示加锁的办法来解决。mysql可反复读是否解决幻读在网上,咱们常常会看到两种说法的文章,有的说mysql可反复读解决了幻读问题的,也有说没解决的。 这么说也对也不对,具体差别在于以后读取操作是快照读还是以后读,如下: 快照读以后读备注 开始时订单1下有两个order_item,别离A和Bselect * from order_item where oid=1(读到A和B)select * from order_item where oid=1(读到A和B)第一次读 另一事务在订单1下插入C并提交select * from order_item where oid=1(读到A和B)select * from order_item where oid=1 for update(读到A、B和C)第二次读下面后果同样在mysql5.7下验证通过,咱们称其中的select xxx for update为以后读,即读取最新的数据,一般的select则是快照读,在mysql中insert、update、delete、select xxx for update都是以后读。 ...

April 10, 2022 · 1 min · jiezi

关于事务:事务回滚后回调

对了加了 @Transactional的办法,当办法抛出异样时会主动回滚。如果咱们此时想在回滚前执行一些办法,如开释锁。能够这么写:/** * 实用于事务办法:事务实现后再开释锁 * * @param key * @param requestId */private void unlockAfterTransaction(String key, String requestId) { TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() { @Override public void afterCompletion(int status) { super.afterCompletion(status); distributeLocker.unlock(key, requestId); log.info("unlock success"); } });}

February 12, 2022 · 1 min · jiezi

关于事务:事务方法执行中断导致锁表

报错信息:数据库插入超时,然而查问失常。 起因剖析:本地debug带事务注解的办法时候,执行到一半之后间接停掉了服务。此时的事务没有失常开释,导致mysql锁住了表。 解决办法: 能够先执行命名查看是否有被锁住的表: show OPEN TABLES where In_use > 0;确认起因后,执行 SELECT * FROM information_schema.innodb_trx 找到锁表的过程id(try_mysql_thread_id字段),而后间接 kill xxx

January 11, 2022 · 1 min · jiezi

关于事务:MySQL事务隔离级别与MVCC

前言本篇文章首先会对数据库事务的几个根底概念进行阐明,次要是事务ACID模型,并发事务带来的问题和事务隔离级别。而后在此基础上,会对MySQL的InnoDB引擎中的一致性非锁定读取(Consistent Nonlocking Reads)进行较为深刻的演示和解析,次要波及MVCC机制,undo log和快照。 参考 《深入浅出MySQL》MySQL官网文档注释一. 事务和事务ACID模型1. 事务概念事务概念如下。 事务是由一组SQL语句组成的逻辑处理单元。即能够将事务了解为一系列的对数据库的操作汇合,这些操作要么全副失效,要么全副不失效。 2. ACID模型事务的ACID模型如下表所示。 ACID属性项解释原子性(Atomicity)事务是一个原子操作单元,其对数据的批改,要么全都执行,要么全都不执行。一致性(Consistent)在事务开始和实现时,数据都必须保持一致状态。即所有相干的数据规定都必须利用于事务的批改,以保持数据的完整性;事务完结时,所有的外部数据结构(如B树索引或双向链表)也都必须是正确的。隔离性(Isolation)数据库系统提供肯定的隔离机制,保障事务在不受内部并发操作影响的“独立”环境执行。即事务处理过程中的中间状态对其它事务是不可见的。持久性(Durable)事务实现之后,事务对于数据的批改是永久性的,即便呈现系统故障也可能放弃。二. 并发事务带来的问题如果事务之间严格依照串行的形式执行,不会呈现并发问题,然而会极大升高对数据库资源的利用率。因而为了减少数据库资源的利用率,进步数据库系统的事务吞吐量,通常事务之间是并发执行的,由此也引入了并发事务带来的问题,如下表所示。 并发事务带来的问题解释脏读(Dirty Reads)一个事务正在对一条记录做批改,在这个事务实现并提交前,这条记录的数据就处于不统一状态,这时,第二个事务来读取同一条记录,如果不加管制,第二个事务会读取这条处于不统一状态的记录,即读取到脏数据,称为脏读。不可反复读(Non-Repeatable Reads)一个事务在读取某些数据后的某个工夫,再次读取以前读过的数据,却发现其读出的数据曾经产生了扭转或某些记录曾经被删除,这种景象称为不可反复读。幻读(Phantom Reads)一个事务按雷同的查问条件从新读取以前检索过的数据,却发现其它事务插入了满足其查问条件的新数据,这种景象称为幻读。三. 事务隔离级别为了解决因为并发事务带来的脏读,不可反复读和幻读的问题,须要借助数据库提供肯定的事务隔离机制,通常有基于乐观锁的加锁机制和基于无锁的多版本并发管制(MultiVersion Concurrency Control, MVCC)。事务隔离的本质就是使事务在肯定水平上串行化执行,事务隔离得越严格,串行化的水平就越高,然而相应的数据库的并发能力就越低,为了解决事务的隔离与并发的矛盾,引入了事务隔离级别这一概念,不同的隔离级别会导致不同的事务并发问题,每种隔离级别的形容如下表所示。 事务隔离级别形容读未提交(Read uncommitted,RU)事务能够感知到其它未提交事务对数据库所做的变更。读已提交(Read committed,RC)事务无奈感知到其它未提交事务对数据库所做的变更。可反复度(Repeatable read,RR)事务在执行过程中,只能看到事务启动时刻数据库的状态,事务无奈感知到其它事务对数据库所做的变更。可序列化(Serializable)事务对数据的操作会加锁,通过加锁使事务串行化执行,是最高事务隔离级别,但数据库的并发能力最低。特地阐明:在MySQL的InnoDB引擎中,以读未提交隔离级别为例,某个事务如果隔离级别是读未提交,并不阐明该事务在提交事务前对数据库所做的变更对其它事务可见,而是该事务查问数据时抉择将其它未提交事务对数据库所做的变更置为可见。即事务隔离级别是事务在查问数据时抉择所有被查数据的一种规定,局部文章中对事务隔离级别的概念进行了混同,故特此说明。 不同的隔离级别下,事务读数据一致性和并发事务带来的问题能够用下表示意。 上面将针对不同的事务隔离级别,基于MySQL的InnoDB引擎进行简略的示例演示。首先创立表,SQL语句如下所示。 CREATE TABLE info( id INT(11) PRIMARY KEY AUTO_INCREMENT, num INT(11) NOT NULL)插入一条数据以供查问,SQL语句如下所示。 INSERT INTO info (num) VALUES (20);第一个示例是读未提交,先将事务2隔离级别设置为READ UNCOMMITTED,事务执行流程如下图所示。 事务2读取到了事务1未提交的数据,在事务1回滚之后,数据库中id为1的数据的num为20,此时事务2读取到的数据成为了脏数据,产生了脏读。 第二个示例是读已提交,先将事务2隔离级别设置为READ COMMITTED,事务执行流程如下图所示。 步骤3中事务1更新了id为1的数据的num为25,步骤4中事务2查问了id为1的数据且num为20,阐明在读已提交事务隔离级别下,事务无奈感知其它未提交事务对数据库的更改。步骤5中事务1提交了事务,步骤6中事务2又查问了id为1的数据且num为25,那么事务2在同一次事务中对同一条数据的两次读取后果不雷同,产生了不可反复读。 进行第三个示例前,先将id为1的数据的num更改回20。 第三个示例是可反复读,先将事务2隔离级别设置为REPEATABLE READ,事务执行流程如下图所示。 事务1更改了id为1的数据的num为25,并提交了事务,事务2在事务1提交事务前后别离执行了一次查问,并且第二次查问后果与第一次查问后果雷同,所以在可反复读隔离级别下解决了不可反复读问题。 进行第四个示例前,先将id为1的数据的num更改回20。 第四个示例仍旧是可反复读,事务执行流程如下图所示。 步骤3中事务1插入了一条num为25的数据,步骤4中事务2执行了一次范畴查问,查问后果不蕴含num为25的数据,步骤5中事务1提交了事务,步骤6中事务2又执行了一次范畴查问,查问后果还是不蕴含num为25的数据,所以在MySQL的InnoDB引擎下将事务隔离级别设置为可反复读时,还能够解决幻读的问题。通常状况下,可反复读隔离级别是无奈解决幻读的,然而MySQL的InnoDB引擎应用了MVCC技术,能够在可反复读隔离级别下,躲避了幻读的问题,对于MVCC技术,将在下一大节进行阐明。 四. 一致性非锁定读取对于一致性非锁定读取的官网概念,能够参见MySQL的官网文档:Consistent Nonlocking Reads。定义如下所示。 A consistent read means that InnoDB uses multi-versioning to present to a query a snapshot of the database at a point in time. The query sees the changes made by transactions that committed before that point in time, and no changes made by later or uncommitted transactions.The exception to this rule is that the query sees the changes made by earlier statements within the same transaction. ...

January 6, 2022 · 2 min · jiezi

关于事务:事务

事务是数据库操作最根本单元,逻辑上一组操作,要么都胜利,如果有一个失败所有操作都失败典型场景:银行转账

July 4, 2021 · 1 min · jiezi

关于事务:电商千万级交易的金手指分布式事务管理

摘要:从古至今,咱们的交易与生产过程 产生着天翻地覆的变动。明天,带大家一起 解密继续千年那些买买买背地的故事。本文分享自华为云社区《揭秘买买买千万级交易背地的那些事》,原文作者:华为云头条 。 上云总动员干货进行时,带你一起揭秘买买买背地的那些事! 从古至今,咱们的交易与生产过程 产生着天翻地覆的变动 明天,云宝想带大家一起 解密继续千年那些买买买背地的故事 遐想远古期间 人们通过以物易物的形式实现生产需要 但常因物品价值不对等而不欢而散 起初呈现货币,从贝壳到铜钱 “买买买”是实现了但钱币难以随身携带 交易变成沉甸甸的“累赘” 宋朝呈现纸币“交子”,大大晋升了交易效率 但随之而来的“伪钞”问题也困扰人们千年 当初,互联网技术的倒退 让网络领取浸透生存的每一个角落 各类交易通过扫码、碰一碰就能领取 但审慎的小伙伴肯定关注过 最早的线上购物,已经呈现买家下单胜利 付了钱却没收到货 卖家接到投诉却没找到订单记录 生生吃了个差评却无处说理 这到底是怎么肥事? 云宝这就带你走近微服务之 为领取操碎了心特别篇 不过,在理解古代交易产生的问题之前 咱们先来看看上面3个内容 Q1:什么是事务?事务是由一组SQL语句组成的逻辑处理单元,可看做是一次大流动由不同小流动组成;它们具备4个属性,即事务ACID属性: 原子性(Atomicity)一致性(Consistency)隔离性(Isolation)持久性(Durability)大家只需重点记住 TA们要么全副胜利要么全副失败 不存在“薛定谔的事务” Q2:什么是分布式事务?单体利用拆分成多个利用后,造成了SOA架构,或者是微服务架构。这时候就变成了一个分布式系统,而依赖分布式系统所产生的事务,就是分布式事务。 划个重点 单体架构下的一般事务因为利用未拆分 所有性能混在一起,牵一动员全身 而微服务架构下的分布式事务则因为利用拆分后 各零碎分工合作,权责明显 Q3:为什么须要分布式事务?给大家看个分布式事务典型场景~ 整个电商购物波及到了4个零碎 从订单零碎开始发动事务 如果在下单这个过程中 仓储零碎最终并没有生成出库记录 那库存零碎应该要勾销扣库存减扣 积分零碎应该也要勾销加积分 TA们能力放弃数据一致性 防止买卖双方“喜剧”的产生 数据不同步 ▼ 分布式事务让数据统一 ▼ 怎么样,也来一款试试吗? 给大家举荐下 华为云分布式事务管理DTM能有机整合整体购物流程 岂但不便买家、卖家、平台治理 而且反对电子商务平安凋敝地倒退 从此和鸡飞狗跳的购物问题say拜拜啦 华为云DTM是华为云分布式事务管理中间件,提供了高牢靠的分布式事务处理能力。反对跨微服务事务、跨库事务、多数据源、非侵入式事务、TCC事务、事务监控、高TPS事务处理能力及数据分析等性能场景,帮忙企业满足外围业务数据(如交易数据)一致性需要。 亮点太多几乎说不完 ...

March 17, 2021 · 1 min · jiezi

关于事务:技术分享-大数据量更新回滚效率提升方法

作者:周启超爱可生北分团队 DBA,次要负责项目前期建设及前期疑难问题反对。做事认真,对事负责。本文起源:原创投稿*爱可生开源社区出品,原创内容未经受权不得随便应用,转载请分割小编并注明起源。咱们常常会遇到操作一张大表,发现操作工夫过长或影响在线业务了,想要回退大表操作的场景。在咱们进行大表操作之后,期待回滚是一个很漫长的过程,只管你可能对晓得一些缩短工夫的办法,处于对生产环境数据完整性的敬畏,也会抉择不做染指。最终抉择不作为的起因大多源于对操作影响的不确定性。实际出真知,上面针对两种次要晋升事务回滚速度的形式进行验证,一种是晋升操作可用内存空间,一种是通过停实例,禁用 redo 回滚形式进行进行验证。 仔细阅读过官网手册的同学,肯定留意到了对于晋升大事务回滚效率,官网提供了两种办法:一是减少 innodb_buffer_pool_size 参数大小,二是正当利用 innodb_force_recovery=3 参数,跳过事务回滚过程。第一种形式比拟温和,innodb_buffer_pool_size 参数是能够动静调整的,可行性也较高。第二种形式相较之下较暴力,但成果较好。 上面咱们看下第一种形式的成果如何:mysql>set global innodb_buffer_pool_size = 1073741824;Query OK, 0 rows affected (0.00 sec)mysql> begin;Query OK, 0 rows affected (0.00 sec)mysql> use sbtest;Database changedmysql> update sbtest1 set k=k+1; Query OK, 16023947 rows affected (7 min 23.23 sec)Rows matched: 16023947 Changed: 16023947 Warnings: 0mysql>mysql> set global innodb_buffer_pool_size = 5368709120;Query OK, 0 rows affected (0.00 sec)mysql> show variables like '%uffer_pool%';+-------------------------------------+----------------+| Variable_name | Value |+-------------------------------------+----------------+| innodb_buffer_pool_chunk_size | 134217728 || innodb_buffer_pool_dump_at_shutdown | ON || innodb_buffer_pool_dump_now | OFF || innodb_buffer_pool_dump_pct | 25 || innodb_buffer_pool_filename | ib_buffer_pool || innodb_buffer_pool_instances | 8 || innodb_buffer_pool_load_abort | OFF || innodb_buffer_pool_load_at_startup | ON || innodb_buffer_pool_load_now | OFF || innodb_buffer_pool_size | 5368709120 |+-------------------------------------+----------------+10 rows in set (0.02 sec)mysql> rollback;Query OK, 0 rows affected (6 min 39.41 sec)最后更新操作用时 7 min 23.23 sec 回滚操作用时 6 min 39.41 sec 相较于更新操作回滚操作耗时缩短了将近一分钟,成果仿佛并不显著。 当然回滚工夫和更新操作工夫进行比照不太谨严,上面对不同大小 innodb_buffer_pool_size 条件状况下更新和回滚操作工夫进行一个汇总。 ...

October 22, 2020 · 2 min · jiezi

关于事务:数据库事务的实现原理

1. 前言都晓得数据库事务有ACID个性(原子性、一致性、隔离型、持久性),本文简略聊一下它们的实现原理。 2. 日志文件2.1. redo logredo log叫做重做日志,是用来实现事务的持久性。该日志文件由两局部组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log),前者是在内存中,后者在磁盘中。 当事务提交之后会把所有批改信息都会存到该日志中。假如有个表叫做tb1(id,username) 当初要插入数据(3,ceshi) start transaction; select balance from bank where name="zhangsan"; // 生成 重做日志 balance=600 update bank set balance = balance - 400; // 生成 重做日志 amount=400 update finance set amount = amount + 400; commit; redo log 有什么作用?mysql 为了晋升性能不会把每次的批改都实时同步到磁盘,而是会先存到Boffer Pool(缓冲池)外头,把这个当作缓存来用。而后应用后盾线程去做缓冲池和磁盘之间的同步。 那么问题来了,如果还没来的同步的时候宕机或断电了怎么办?还没来得及执行下面图中红色的操作。这样会导致丢局部已提交事务的批改信息! 所以引入了redo log来记录已胜利提交事务的批改信息,并且会把redo log长久化到磁盘,零碎重启之后在读取redo log复原最新数据。 总结:redo log是用来复原数据的 用于保障,已提交事务的长久化个性。 2.2. undo logundo log 叫做回滚日志,用于记录数据被批改前的信息。他正好跟后面所说的重做日志所记录的相同,重做日志记录数据被批改后的信息。undo log次要记录的是数据的逻辑变动,为了在产生谬误时回滚之前的操作,须要将之前的操作都记录下来,而后在产生谬误时才能够回滚。 还用下面那两张表 ...

September 27, 2020 · 1 min · jiezi

关于事务:回滚

1.mySQL中的事务提交,mySQL中的事务提条默认是主动提交.2.回滚就是将数据恢复到原来的样子3.事务提交用commit.事务一旦提交,就不能够批改.4.若执行过程中出错,则不提交,事务须要回滚5.事务回滚和提交只会执行一个,提交就是失常执行,回滚就是不失常执行.

September 17, 2020 · 1 min · jiezi

关于事务:事务不好意思你被隔离了

事务的隔离级别数据库个别有四种个性:原子性、一致性、隔离性和持久性。而数据库的隔离级别就是针对其中的隔离性而言。 隔离级别也有四种:未提交读、提交读、可反复读、串行化。也不是所有数据库都反对事务的,甚至同一数据库不同存储引擎事务都不是一样的,例如MySQL数据库,外面InnoDB 引擎反对事务,而MyISAM 引擎不反对事务。 而在咱们利用层面,例如spring框架基于数据库事务的隔离级别也提供了本人的隔离级别,它有五种,其中四种和数据库一一对应,还有一种是DEFAULT,它示意应用数据库默认的隔离级别。对于不同数据库,默认的隔离级别可能是不一样的,例如MySQL数据库默认隔离级别是可反复读,而Oracle数据库是提交读。 上面来具体看看四种隔离级别是什么样的,代码是基于spring事务注解来管制事务的隔离级别。 未提交读(READ_UNCOMMITTED)此级别属于最低隔离级别,能够读取其余事务未提交的数据,相当于没有隔离,个别不必此种隔离级别。 例如上面这个例子: @Test@Transactional(isolation = Isolation.READ_UNCOMMITTED)public void select() throws Exception { List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from book where id = 1 "); System.out.println(maps);}@Test@Transactionalpublic void update() throws Exception { jdbcTemplate.update("update book set name = '三体2' where id = 1"); Thread.sleep(30000); throw new Exception("异样回滚");}首先执行update办法,外面尽管执行了批改操作,然而期待30s后抛出了异样,事务回滚,而在回滚之前执行select办法,发现读取到了 name='三体2'的后果。阐明:READ_UNCOMMITTED隔离级别能够读取到其余事务还没提交的数据,造成脏读。 读已提交(READ_COMMITTED)此级别只能读取曾经提交的数据,然而读取一行数据时,其余事务能够批改此行数据,再次读取时和上次不一样(不可反复读)。这是Oracle等数据库默认隔离级别。 示例: @Test@Transactional(isolation = Isolation.READ_COMMITTED)public void select() throws Exception { List<Map<String, Object>> maps = jdbcTemplate.queryForList("select * from book where id = 1 "); System.out.println("第一次:"+maps); Thread.sleep(30000); maps = jdbcTemplate.queryForList("select * from book where id = 1"); System.out.println("第二次:"+maps);}@Test@Transactionalpublic void update() throws Exception { jdbcTemplate.update("update book set name = '三体3' where id = 1");}首先执行select办法,输入第一次后果,此时name='三体2',而后进入睡眠;接着执行update办法,批改这条数据当前,select办法里第二次输入,此时name='三体3',造成了同一个事务中,两次读取后果不一样。阐明:READ_COMMITTED隔离级别尽管只能读取已提交的数据,然而读取时,其余事务还能够批改此数据(不可反复读)。 ...

August 11, 2020 · 1 min · jiezi

关于事务:spring事务咋和新冠病毒一样还会传染

什么是事务?数据库事务是指一系列紧密操作,要么全副胜利,要么全副失败。它有四种个性:原子性、一致性、隔离性和持久性。 而spring事务是封装在数据库事务之上的一种事务处理机制,它有两种治理形式:编程式事务和申明式事务。在平时应用中,咱们大多应用@Transactional申明式事务来治理,这也是spring举荐的形式,上面例子也对立采纳此种形式。 上面咱们次要来看看spring事务的流传机制 spring事务的流传机制spring事务的流传机制有七种:REQUIRED、REQUIRES_NEW、NESTED、SUPPORTS、NOT_SUPPORTED、MANDATORY和NEVER。 首先要晓得事务的流传指的是一个办法调用另外一个办法并将事务传递给它,而流传机制是针对被调用者,管制它是否被流传或者被怎么流传。注:前面屡次提到 此办法在/不在事务中,指的是调用者是否开启了事务。 上面咱们来仔细分析一下这几种传播方式。 REQUIRED(有事务则退出,没有则创立)REQUIRED是spring事务的默认形式,如果以后办法不在事务中,就创立一个新的事务;如果以后办法在事务中,就退出到这个事务中。 举个例子,咱们操作book书籍表和title章节表,先插入book表,而后再插入title表(上面几种传播方式都以这两张表为例)。BookServiceImpl中办法(调用者)调用TitleServiceImpl中办法(被调用者)。上面分两种状况: 1、调用者有事务 @Slf4j@Service@AllArgsConstructorpublic class BookServiceImpl implements BookService { private final BookMapper bookMapper; private final TitleService titleService; @Override @Transactional public void bookTransaction() { String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("调用者中事务:{}", transactionName); bookMapper.insert(new Book().setAuthor("zpg")); //流传事务 titleService.titleTransaction(); }}@Slf4j@Service@AllArgsConstructorpublic class TitleServiceImpl implements TitleService { private final TitleMapper titleMapper; @Override @Transactional(propagation = Propagation.REQUIRED) public void titleTransaction() { String transactionName = TransactionSynchronizationManager.getCurrentTransactionName(); log.info("被调用者中事务:{}", transactionName); titleMapper.insert(new Title().setName("第一章")); }}// 输入,被调用者应用的是调用者的事务调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest2、调用者无事务 ...

August 11, 2020 · 2 min · jiezi

为什么要避免大事务以及大事务如何解决

什么是大事务运行工夫比拟长,长时间未提交的事务就能够称为大事务 大事务产生的起因操作的数据比拟多大量的锁竞争事务中有其余非DB的耗时操作。。。大事务造成的影响并发状况下,数据库连接池容易被撑爆锁定太多的数据,造成大量的阻塞和锁超时执行工夫长,容易造成主从提早回滚所须要的工夫比拟长undo log收缩。。。如何查问大事务注:本文的sql的操作都是基于mysql5.7版本 以查问执行工夫超过10秒的事务为例: select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>10如何防止大事务通用解法在一个事务外面, 防止一次解决太多数据在一个事务外面,尽量避免不必要的查问在一个事务外面, 防止耗时太多的操作,造成事务超时。一些非DB的操作,比方rpc调用,音讯队列的操作尽量放到事务之外操作基于mysql5.7的解法在InnoDB事务中,行锁是在须要的时候才加上的,但并不是不须要了就立即开释,而是要等到事务完结时才开释。如果你的事务中须要锁多个行,要把最可能造成锁抵触、最可能影响并发度的锁尽量往后放通过SETMAX_EXECUTION_TIME命令, 来管制每个语句查问的最长工夫,防止单个语句意外查问太长时间监控 information_schema.Innodb_trx表,设置长事务阈值,超过就报警/或者kill在业务功能测试阶段要求输入所有的general_log,剖析日志行为提前发现问题设置innodb_undo_tablespaces值,将undo log拆散到独立的表空间。如果真的呈现大事务导致回滚段过大,这样设置后清理起来更不便附录查问事务相干语句注:sql语句都是基于mysql5.7版本 # 查问所有正在运行的事务及运行工夫select t.*,to_seconds(now())-to_seconds(t.trx_started) idle_time from INFORMATION_SCHEMA.INNODB_TRX t# 查问事务详细信息及执行的SQLselect now(),(UNIX_TIMESTAMP(now()) - UNIX_TIMESTAMP(a.trx_started)) diff_sec,b.id,b.user,b.host,b.db,d.SQL_TEXT from information_schema.innodb_trx a inner join information_schema.PROCESSLIST bon a.TRX_MYSQL_THREAD_ID=b.id and b.command = 'Sleep'inner join performance_schema.threads c ON b.id = c.PROCESSLIST_IDinner join performance_schema.events_statements_current d ON d.THREAD_ID = c.THREAD_ID;# 查问事务执行过的所有历史SQL记录SELECT ps.id 'PROCESS ID', ps.USER, ps.HOST, esh.EVENT_ID, trx.trx_started, esh.event_name 'EVENT NAME', esh.sql_text 'SQL', ps.time FROM PERFORMANCE_SCHEMA.events_statements_history esh JOIN PERFORMANCE_SCHEMA.threads th ON esh.thread_id = th.thread_id JOIN information_schema.PROCESSLIST ps ON ps.id = th.processlist_id LEFT JOIN information_schema.innodb_trx trx ON trx.trx_mysql_thread_id = ps.id WHERE trx.trx_id IS NOT NULL AND ps.USER != 'SYSTEM_USER' ORDER BY esh.EVENT_ID; # 简略查问事务锁 select * from sys.innodb_lock_waits # 查问事务锁详细信息 SELECT tmp.*, c.SQL_Text blocking_sql_text, p.HOST blocking_host FROM ( SELECT r.trx_state wating_trx_state, r.trx_id waiting_trx_id, r.trx_mysql_thread_Id waiting_thread, r.trx_query waiting_query, b.trx_state blocking_trx_state, b.trx_id blocking_trx_id, b.trx_mysql_thread_id blocking_thread, b.trx_query blocking_query FROM information_schema.innodb_lock_waits w INNER JOIN information_schema.innodb_trx b ON b.trx_id = w.blocking_trx_id INNER JOIN information_schema.innodb_trx r ON r.trx_id = w.requesting_trx_id ) tmp, information_schema.PROCESSLIST p, PERFORMANCE_SCHEMA.events_statements_current c, PERFORMANCE_SCHEMA.threads t WHERE tmp.blocking_thread = p.id AND t.thread_id = c.THREAD_ID AND t.PROCESSLIST_ID = p.id 参考MySQL-长事务详解 ...

July 17, 2020 · 1 min · jiezi