1、什么是事务
事务-Transaction:一个最小的不可再分的工作单元;通常一个事务对应一个完整的业务(例如银行账户转账业务),该业务就是一个最小的工作单元。
引入事务的主要目的:事务会把数据库从一种一致状态转换为另一种一致状态,在数据库提交工作时,可以确保所有的修改都已经保存
事务必须满足四个特性:ACID
1.1、事务的四个特性
1.1.1、 原子性(atomicity)
原子性指整个数据库事务是不可分割的工作单元。
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
只有事务中所有数据库操作都执行成功,才算是整个事务成功。
1.1.2、 一致性(consistency)
概念
一致性指事务将数据库从一种状态转变为下一种一致的状态。
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
例子
比如名字字段有唯一约束,也就是姓名不能重复,不能说事务提交后,姓名变得可以重复了,这样就破坏了一致性
1.1.3、隔离性(durability)
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
【事务隔离级别】
读未提交(read uncommitted):一个事务还没提交时,它做的变更就能被别的事务看到。
读提交(read committed):一个事务提交之后,它做的变更才会被其他事务看到。
可重复读(repeatable read):一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。💥默认级别
串行化(serializable):顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
【事务隔离级别读取例子】
“读未提交”—— V1=V2=V3=2
因为B事务未提交,改变后的值就会直接被其他事务看到。
“读提交”——V1=1,V2=V3=2
因为在B事务提交之后,改变后的值才可以被看到。
“可重复读”——V1=V2=1,V3=2。
事务A在开始时读到的是未更新后的值,所以整个事务期间都是1,然后事务A结束,B在A之前结束了,所以V3读到了事务B更新后的值。
“串行化”——V1=V2=1,V3=2
事务B执行“将1改成2”的时候,会被锁住(因为认为事务的开始是从第一条语句开始执行的)。直到事务A提交后,事务B才可以继续执行。所以从A的角度看, V1、V2值是1,V3的值是2。
1.1.4、持久性
事务处理结束后,对数据的修改就是永久的,即便发生系统宕机也能恢复数据,从事务本身角度来保证事务的永久性。
当然如果是外部原因可能无法避免。
1.2、事务的分类
扁平事务(Flat Transactions)
带有保存点的扁平事务(Flat Transactions with Savepoints)
链事务(Chained Transactions)
嵌套事务(Nested Transactions)
分布式事务(Distributed Transactions)
1.2.1、扁平事务(Flat Transactions)
扁平事务(Flat Transaction)是事务类型中最简单的一种, 但在实际生产环境中,这可能是使用最为频繁的事务。
在扁平事务中, 所有操作都处于同一层次, 其由BEGIN WORK开始, 由COMMIT WORK或ROLLBACK WORK结束, 其间的操作是原子的,要么都执行, 要么都回滚。
因此扁平事务是应用程序成为原子操作的基本组成模块。
扁平事务的三种结果
特点
使用简单,实际生产环境中使用最为频繁,所以每个数据库系统都实现了对扁平事务的支持
限制不能提交或者回滚事务的某一部分,或分几个步骤提交。
扁平事务无法满足情况
用户旅行的的流程安排为:
预定杭州到上海的高铁
上海浦东国际机场坐飞机,预定去米兰的航班
在米兰转货车前往佛罗伦萨,预定去佛罗伦萨的火车🚆
然后执行到c的时候,发现飞机到米兰时间太晚,没有当天火车,打算第二天出发,但是这个时候如果我们回滚之前a,b,c的操作,代价比较大,所以这个时候推出带有保存点的扁平事务
1.2.2、带保存点的扁平事务
为什么要有带有保存点的扁平事务
带有保存点的扁平事务,除了支持扁平事务支持的操作外,允许在事务执行过程中回滚同一事务中较早的一个状态。
因为某些事务可能在执行过程中出现的错误并不会导致所有的操作都无效,放弃整个事务不合乎要求,开销太大。
保存点:用来通知事务系统应该记住事务当前的状态,以便当之后发生错误时,事务能回到保存点当时的状态。
什么是带有保存点的扁平事务
扁平的事务:隐式的设置了一个保存点。然而整个事务中,只有这一个保存点,因此,回滚只能会滚到事务开始时的状态。
带有保存点的扁平事务:有多个保存点,保存点用SAVE WORK函数来建立,通知系统记录当前的处理状态。当出现问题时,保存点能用作内部的重启动点,根据应用逻辑,决定是回到最近一个保存点还是其他更早的保存点。
保存点在事务内部是递增的,而且是单调递增
带保存点的扁平事务具体执行
图中经历了两次回滚,第一个回滚到保存点2的位置,第二次回滚到保存点7的位置
java中保存点的使用
例子
原来的数据
事务执行
begininsert into database_lock(id,resource) VALUES(4,1)insert into database_lock(id,resource) VALUES(222,1)SAVEPOINT insert2insert into database_lock(id,resource) VALUES(333,1)ROLLBACK to insert2insert into database_lock(id,resource) VALUES(444,1)commit
执行后的结果
1.2.3、链事务
为什么要有链事务
链事务可视为保存点模式的一种变种,带有保存点的扁平事务,当发生系统崩溃是,所有的的保存点都将消失,因为其保存点是易失的,这意味着当进行恢复时,事务需要从开始处重新执行,而不能从最近的一个保存点继续执行。所以提出了链事务
什么是链事务
链事务的思想是:在提交一个事务时,释放不需要的数据对象,将必要的处理上下文隐式地传给下一个要开始的事务,提交事务操作和开始下一个事务操作 将合并为一个原子操作,这意味着下一个事务将看到上一个事务的结果,就好像一个事务中进行的一样,如图显示了链事务的工作方式:
链事务只能回滚到当前事务,在commit后就会是否当前事务所持有的锁。
1.2.4、嵌套事务
嵌套事务 是一个层次结构框架,由一个顶层事务(top-level transaction)控制着各个层次的事务,顶层事务之下嵌套的事务被称为子事务,其控制每一个局部的变换,结构如下:
Moss对嵌套事务的定义:
1、嵌套事务是由若干事务组成的一颗树,子树既可以是嵌套事务,也可以是扁平事务。 2、处在叶节点的事务是扁平事务。但每个子事务从根到叶节点的距离可以是不同的。 3、位于根节点的事务成为顶层事务,其他事务成为子事务。事务的前驱(predecessor)为父事务(parent),事务的下一层成为儿子事务(child) 4、子事务既可以提交可以回滚,但是它的提交操作并不会马上生效,除非其父事务已经提交。因此,任何子事务都在顶层事务提交后才真正提交。 5、树中的任意一个事务的回滚会引起其他的所有子事务一同回滚,故子事务仅保留A、C、I特性,不具备D的特性。
Moss理论中,实际的工作是由叶子节点来完成的,即只有叶子节点的事务才能访问数据库,发送消息,获取其他类型的资源。而高层的事务仅负责逻辑控制,决定何时调用相关的子事务。即使一个系统不支持嵌套事务,可以通过保存点技术来模拟嵌套事务。如图
1.2.5、分布式事务
分布式事务通常是一个分布式环境下运行的扁平事务,因此需要根据数据所在位置访问网络中的不同节点。
假如一个用户在ATM机上进行银行的转账操作,例如持卡人从招商银行存储卡转账10 000 元到工商银行的存储卡。
这种情况下,可以将ATM机视为节点A,招商银行的后台数据库视为节点B,工商银行的后台数据库视为C,这个转账的操作可分解为以下的步骤
节点A发出转账命令
节点B执行存储卡中的余额减去10 000
节点C执行存储卡终端的余额增加10 000
节点A通知用户操作完成或者节点A通知用户操作失败
这里需要使用到分布式事务,因为节点A不能通过一台数据库就完成任务,其需要访问网络中两个节点的数据库,而在每个节点的数据库执行的实务操作有都是扁平的,对于分布式事务,其同样需要满足ACID特性,要么都发生,要么都失败。对于上述例子,如果2 3 步中任何一个操作失败,都会导致整个分布式事务回滚,若非这样,结果非常可怕。
对于InnoDB存储引擎来说,其支持扁平事务,带有保存点的事务,链事务,分布式事务,而不支持嵌套事务,不过可以通过带保存点的事务来模拟串行的嵌套事务。
3、事务的控制语句
Mysql的命令行默认设置下,事务自动提交,也就是执行完sql语句后会立马执行commit操作。
SET AUTOCOMMIT=0 禁用自动提交
1、START TRANSACTION 或 BEGIN 开始一项事务。
2、COMMIT 或者 COMMIT WORK 提交事务,
3、ROLLBACK | ROLLBACK WORK 回滚事务。
4、SAVEPOINT identifier : SAVEPOINT 允许一个事务中创建一个保存点,一个事务中可以有多个保存点
5、RELEASE SAVEPOINT identifer :删除一个事务的保存点,当没有一个保存点执行这句语句时,会抛出一个异常
6、ROLLBACK TO[SAVEPOINT] identifer :与 savepoint 命令一起使用,将事务回滚到标记点,而不回滚到标记点之前的任何工作。
7、SET TRANSACTION :设置事务隔离级别
8、SET AUTOCOMMIT 修改当前连接的方式,0 代表需要手动提交事务,需要使用明确的命令提交事务,1代表自动提交事务。
4、隐式提交SQL语句
DDL语句:ALTER DATABASE UPGRADE DATA DIRECTORY NAME,ALTER EVENT, ALTER PROCEDURE, ALTER TABLE, ALTER VIEW,CREATE DATABASE, CREATE EVENT, CREATE INDEX, CREATE PROCEDURE, CREATE TABLE, CREATE TRIGGER, CREATE VIEW,DROP DATABASE, DROP EVENT, DROP INDEX, DROP PROCEDURE,DROP TABLE, DROP TRIGGER, DROP VIEW, RENAME TABLE,TRUNCATE TABLE。
用来隐式地修改 MySQL架构的操作:CREATE USER、DROP USER、GRANT、RENAME USER、REVOKE、SET PASSWORD。
管理语句:ANALYZE TABLE、CACHE INDEX、CHECK TABLE、LOAD INDEX INTO CACHE、OPTIMIZE TABLE、REPAIR TABLE。
5、事务并发产生的问题
5.1、脏读(Dirty Read)
什么是脏读?
事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
例子
A事务执行过程中,B事务读取了A事务的修改。
但是由于某些原因,A事务可能没有完成提交,发生RollBack了操作,则B事务所读取的数据就会是不正确的。这个未提交数据就是脏读(Dirty Read)。脏读产生的流程如下:
5.2、不可重复读(Nonrepeatable Read)
B事务读取了两次数据,在这两次的读取过程中A事务修改了数据,B事务的这两次读取出来的数据不一样。B事务这种读取的结果,即为不可重复读(Nonrepeatable Read)。不可重复读的产生的流程如下:
💥特殊情况(没有避免的)
不可重复读有一种特殊情况,两个事务更新同一条数据资源,后完成的事务会造成先完成的事务更新丢失。这种情况就是大名鼎鼎的第二类丢失更新。
所以这个就导致了事务A的提交消失了。
主流的数据库已经默认屏蔽了第一类丢失更新问题(即:后做的事务撤销,发生回滚造成已完成事务的更新丢失),但我们编程的时候仍需要特别注意第二类丢失更新。
5.3、幻读(Phantom Read)
B事务读取了两次数据,在这两次的读取过程中A事务添加了数据,B事务的这两次读取出来的集合不一样。幻读产生的流程如下:
可重复读下的幻读
5.4、事务隔离级别和并发问题的关系
事务隔离级别
6、分布式事务
6.1、Mysql分布式事务
InnoDB提供了对XA事务的支持,通过XA事务来支持分布式事务的实现
什么是分布式事务
分布式事务:允许多个独立的事务资源(Transational resources)参与到一个全局的事务中,事务资源通常是关系型数据库系统,也可以是其他类型的资源。
使用分布式事务时要求是serializable(串行化)
全局事务:控制和协调各计算机结点上的子事务的执行,从而完成该事务处理任务的事务。一个分布式事务在执行时将被分解为若干在各计算机节点上的数据库系统中执行的操作序列(子事务)
什么是分布式事务
X/Open XA事务是由一个或多个资源管理器(Resource Manager)、一个事务管理器(Transaction Manager)以及一个应用程序组成
资源管理器(resource manager):用来管理系统资源,是通向事务资源的途径。数据库就是一种资源管理器。资源管理还应该具有管理事务提交或回滚的能力。
事务管理器(transaction manager):事务管理器是分布式事务的核心管理者。事务管理器与每个资源管理器(resource manager)进行通信,协调并完成事务的处理。事务的各个分支由唯一命名进行标识
应用程序(Application Program):定义事务的边界,指定全局事务中的操作
在MYSQL当中,资源管理器就是mysql数据库,事务管理器就是mysql服务器的客户端
XA事务语法
XA {START|BEGIN} xid [JOIN|RESUME] 启动一个XA事务 (xid 必须是一个唯一值; [JOIN|RESUME] 字句不被支持)
XA END xid [SUSPEND [FOR MIGRATE]] 结束一个XA事务 ( [SUSPEND [FOR MIGRATE]] 字句不被支持)
XA PREPARE xid 准备
XA COMMIT xid [ONE PHASE] 提交XA事务
XA ROLLBACK xid 回滚XA事务
XA RECOVER 查看处于PREPARE 阶段的所有XA事务
6.2、两阶段提交
6.2.1、准备阶段(投票阶段,prepare)
事务询问
协调者 向所有的 参与者 发送事务预处理请求,称之为Prepare,并开始等待各参与者的响应。
执行本地事务
各个 参与者 节点执行本地事务操作,但在执行完成后并不会真正提交数据库本地事务,而是先向 协调者 报告说:“我这边可以处理了/我这边不能处理”。
各个参与者向协调者反馈事务询问的响应
如果 参与者 成功执行了事务操作,那么就反馈给协调者 Yes 响应,表示事务可以执行,如果没有 参与者 成功执行事务,那么就反馈给协调者 No 响应,表示事务不可以执行。
6.2.2、提交阶段(执行阶段,commit)
协调者向参与者发送commit/rollback请求
① 发送commit情况: 如果所有参与者都在第一阶段反馈yes的请求,协调者 向 所有参与者 节点发出Commit请求.
② 发送rollback情况:任何一个参与者向协调者反馈了No 响应,或者等待超时之后,协调者尚未收到所有参与者的反馈响应,向参与者发送回滚(rollback)请求
参与者接收请求并执行
参与者根据事务管理器的指令执行提交或者回滚操作,并释放事务处理过程中使用的锁资源。注意:必须在最后阶段释放锁资源。-
6.2.3、2PC图示
6.2.4、2PC的问题**
同步阻塞 :所有事务参与者在等待其它参与者响应的时候都处于同步阻塞状态,无法进行其它操作。
单点问题:协调者在 2PC 中起到非常大的作用,发生故障将会造成很大影响。特别是在阶段二发生故障,所有参与者会一直等待状态,无法完成其它操作。
数据不一致:在阶段二,如果协调者只发送了部分 Commit 消息,此时网络发生异常,那么只有部分参与者接收到 Commit 消息,也就是说只有部分参与者提交了事务,使得系统数据不一致。
太过保守:任意一个节点失败就会导致整个事务失败,没有完善的容错机制。
6.3、3PC
6.3.1、为什么要有3PC
引入超时机制。同时在协调者和参与者中都引入超时机制。
3PC把2PC的准备阶段再次一分为二,这样三阶段提交就有CanCommit、PreCommit、DoCommit三个阶段
6.3.2、CanCommit阶段
协调者向参与者发送commit请求,参与者如果可以提交就返回Yes响应,否则返回No响应。
事务询问:协调者向参与者发送CanCommit请求。询问是否可以执行事务提交操作。然后开始等待参与者的响应。
响应反馈:参与者接到CanCommit请求之后,正常情况下,如果其自身认为可以顺利执行事务(会尝试获取数据库锁),则返回Yes(ACK)响应,并进入预备状态。否则反馈No(Abort)
6.3.3、PreCommit阶段
协调者根据参与者的反应情况来决定是否可以记性事务的PreCommit操作。根据响应情况,有以下两种可能。
假如协调者从所有的参与者获得的反馈都是Yes(ACK)响应,那么就会执行事务的预执行。
① 发送预提交请求:协调者向参与者发送PreCommit请求,并进入Prepared阶段。
② 事务预提交:参与者接收到PreCommit请求后,会执行事务操作,并将undo和redo信息记录到事务日志中。
③ 响应反馈:如果参与者成功的执行了事务操作,则返回ACK响应,同时开始等待最终指令。
假如有任何一个参与者向协调者发送了No(Abort)响应,或者等待超时之后,协调者都没有接到参与者的响应,那么就执行事务的中断(直接进入到doCommit阶段)。
① 发送中断请求:协调者向所有参与者发送abort请求。
② 中断事务:参与者收到来自协调者的abort请求之后(或超时之后,仍未收到协调者的请求),执行事务的中断。
6.3.4、doCommit阶段
该阶段进行真正的事务提交,分为两种情况
1、如果协调证收到所有参与者的事务执行后的ACK响应,则发生如下事情
① 发送提交请求:协调接收到参与者发送的ACK响应,那么他将从预提交状态进入到提交状态。并向所有参与者发送doCommit请求。
② 事务提交:参与者接收到doCommit请求之后,执行正式的事务提交。并在完成事务提交之后释放所有事务资源。
③ 响应反馈:事务提交完之后,向协调者发送Ack响应。
④ 完成事务:协调者接收到所有参与者的ack响应之后,完成事务。
2、如果协调者没有接收到参与者发送的ACK响应(可能是接受者发送的不是ACK响应,也可能响应超时),那么就会执行中断事务。
① 发送中断请求:协调者向所有参与者发送abort请求
② 事务回滚:参与者接收到abort请求之后,利用其在阶段二记录的undo信息来执行事务的回滚操作,并在完成回滚之后释放所有的事务资源。
③ 反馈结果:参与者完成事务回滚之后,向协调者发送ACK消息
④ 中断事务:协调者接收到参与者反馈的ACK消息之后,执行事务的中断。
如果参与者无法及时接收到来自协调者的doCommit或者abort请求时,会在等待超时之后,会继续进行事务的提交。
【参考博客】
6.3.5、3PC的优点
1、降低同步阻塞
在3PC中,第一阶段并没有让参与者直接执行事务,而是在第二阶段才会让参与者进行事务的执行。大大降低了阻塞的概率和时长。并且,在3PC中,如果参与者未收到协调者的消息,那么他会在等待一段时间后自动执行事务的commit,而不是一直阻塞。
2、提升了数据一致性
2PC中有一种情况会导致数据不一致,如在2PC的阶段二中,当协调者向参与者发送commit请求之后,发生了网络异常,只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据不一致性的现象。
3PC中,如果参与者没有收到协调者的消息时,他不会一直阻塞,过一段时间之后,他会自动执行事务。这就解决了那种协调者发出commit之后。
6.3.6、3PC的缺点
在doCommit阶段,如果参与者无法及时接收到来自协调者的doCommit或者abort请求时,会在等待超时之后,会继续进行事务的提交。
所以,由于网络原因,协调者发送的abort响应没有及时被参与者接收到,那么参与者在等待超时之后执行了commit操作。这样就和其他接到abort命令并执行回滚的参与者之间存在数据不一致的情况。
6.4、补偿事务(TCC)
6.4.1、什么是TCC
TCC:try-confirm-cancel,针对每个操作都要注册一个与其对应的确认(Try)和补偿(Cancel)
TCC的三个阶段
TCC其实分为两个阶段:Try阶段、Confirm/Cancel阶段
🕐 Try 阶段:尝试执行,完成所有业务检查(一致性),预留必需业务资源(准隔离性)
🕑 Confirm 阶段:主要是对业务系统做确认提交,Try阶段执行成功并开始执行 Confirm阶段时,默认 Confirm阶段是不会出错的。即:只要Try成功,Confirm一定成功。
🕒 Cancel 阶段:主要是在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
6.4.2、TCC的示例
Tom需要给Tracy转10元,需要考虑的事情
需要确保Tom账户余额不少于10元。
需要确保账户余额的正确性,例如:假设Tom只有10元钱,但是Tom同时给Tracy、Angle转账10元;Tom给其他人转账时,也可能收到其他人转过来的钱,此时账户的余额不能出现错乱(Tracy账户也面临过类似的问题)
当并发量比较大时,要能够确保性能。
当使用TCC解决这种事务时
具体处理逻辑
TCC的三个阶段
优点: 跟2PC比起来,实现以及流程相对简单了一些,但数据的一致性比2PC也要差一些
缺点: 缺点还是比较明显的,在2,3步中都有可能失败。TCC属于应用层的一种补偿方式,所以需要程序员在实现的时候多写很多补偿的代码,在一些场景中,一些业务流程可能用TCC不太好定义及处理。
TCC与2PC的区别
XA是资源层面的分布式事务,强一致性,在两阶段提交的整个过程中,一直会持有资源的锁。
XA事务中的两阶段提交内部过程是对开发者屏蔽的,回顾我们之前讲解JTA规范时,通过UserTransaction的commit方法来提交全局事务,这只是一次方法调用,其内部会委派给TransactionManager进行真正的两阶段提交,因此开发者从代码层面是感知不到这个过程的。而事务管理器在两阶段提交过程中,从prepare到commit/rollback过程中,资源实际上一直都是被加锁的。如果有其他人需要更新这两条记录,那么就必须等待锁释放。
TCC是业务层面的分布式事务,最终一致性,不会一直持有资源的锁。
TCC中的两阶段提交并没有对开发者完全屏蔽,也就是说从代码层面,开发者是可以感受到两阶段提交的存在。如上述航班预定案例:在第一阶段,航空公司需要提供try接口(机票资源预留)。在第二阶段,航空公司提需要提供confirm/cancel接口(确认购买机票/取消预留)。开发者明显的感知到了两阶段提交过程的存在。try、confirm/cancel在执行过程中,一般都会开启各自的本地事务,来保证方法内部业务逻辑的ACID特性。
【参考博客1】
【参考博客2】
7、长事务
事务隔离实现——回滚日志3.1 undoLog
回滚日志,保存了事务发生之前的数据的一个版本,可以用于回滚,同时可以提供多版本并发控制下的读(MVCC),也即非锁定读。
存储的内容
逻辑格式的日志,在执行undo(回滚)的时候,仅仅是将数据从逻辑上恢复至事务之前的状态,而不是从物理页面上操作实现的,这一点是不同于redo log的。
事务开始之前,将当前是的版本生成undo log,undo 也会产生 redo 来保证undo log的可靠性
什么时候删除
当事务提交之后,undo log并不能立马被删除,
而是放入待清理的链表,由purge线程判断是否由其他事务在使用undo段中表的上一个事务之前的版本信息,决定是否可以清理undo log的日志空间。
3.2 为什么不推荐使用长事务
长事务意味着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面它可能用到的回滚记录都必须保留,这就会导致大量占用存储空间。
4.事务启动
显式启动事务语句, begin 或 start transaction。配套的提交语句是commit,回滚语句是rollback。
set autocommit=0,这个命令会将这个线程的自动提交关掉。意味着如果你只执行一个select语句,这个事务就启动了,而且并不会自动提交。这个事务持续存在直到你主动执行commit 或 rollback 语句,或者断开连接。
5、如何避免长事务对业务的影响?
5.1、应用开发端
确认是否使用了set autocommit=0。这个确认工作可以在测试环境中开展,把MySQL的general_log开起来,然后随便跑一个业务逻辑,通过general_log的日志来确认。一般框架如果会设置这个值,也就会提供参数来控制行为,你的目标就是把它改成1。
确认是否有不必要的只读事务。有些框架会习惯不管什么语句先用begin/commit框起来。我见过有些是业务并没有这个需要,但是也把好几个select语句放到了事务中。这种只读事务可以去掉。
业务连接数据库的时候,根据业务本身的预估,通过SET MAX_EXECUTION_TIME(控制select的时间,能有效控制在主库的慢查询情况)命令,来控制每个语句执行的最长时间,避免单个语句意外执行太长时间。
5.2、数据库端
监控information_schema.Innodb_trx表,设置长事务阈值,超过就报警/或者kill;
Percona的pt-kill这个工具不错,推荐使用;了解
在业务功能测试阶段要求输出所有的general_log,分析日志行为提前发现问题;
如果使用的是MySQL5.6或者更新版本,把innodb_undo_tablespaces设置成2(或更大的值)。如果真的出现大事务导致回滚段过大,这样设置后清理起来更方便。了解
5.3、general_log日志
将所有到达MySQL Server的SQL语句记录下来。
开启general_log日志步骤:/u010735147/article/details/81871560