关于MySQL事务的一些总结

ACID

原子性、一致性、隔离性、持久性

事务级别

读未提交:一个事务还没提交时,它做的变更就能被别的事务看到

读提交:一个事务提交之后,它做的变更才会被其他事务看到

可重复读:一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的

串行化:对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

事务隔离的实现

在实现上,数据库里面会"创建"一个视图,访问的时候以视图的逻辑结果为准。在“可重复读”隔离级别下,这个视图是在事务启动时"创建"的,整个事务存在期间都用这个视图。在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;而“串行化”隔离级别下直接用加锁的方式来避免并行访问。

每一个事务均由一个唯一ID 叫做transaction id。它是事务启动的时候向Innodb事务系统申请的,并且是顺序递增的。

MySql中的数据有多个版本,每个版本都有一个row trx_id,该row trx_id就是写入该数据的事务ID,并且该版本数据还存在对应的undolog,通过对应的undolog即可获得上一个版本的数据。

InnoDB在“创建”一致性视图的瞬间, 构造一个视图保存当前正在“活跃”的所有事务 ID。“活跃”指的就是,启动了但还没提交。数组里面事务 ID 的最小值记为低水位,当前系统里面已经创建过的事务 ID 的最大值加 1 记为高水位。

这个视图数组和高水位,就组成了当前事务的一致性视图(read-view)。而数据版本的可见性规则,就是基于数据的 row trx_id 和这个一致性视图的对比结果得到的,这个视图数组把所有的 row trx_id 分成了几种不同的情况,如下:

这样,对于当前事务的启动瞬间来说,一个数据版本的 row trx_id,有以下几种可能:

1 如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的

2 如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的

3 如果落在黄色部分,那就包括两种情况

     a. 若 row trx_id 在数组中,表示这个版本是由还没提交的事务生成的,不可见

     b. 若 row trx_id 不在数组中,表示这个版本是已经提交了的事务生成的,可见。

上述具体逻辑翻译成比对规则如下:

1 版本未提交,不可见

2 版本已提交,但是是在视图创建后提交的,不可见

3 版本已提交,而且是在视图创建前提交的,可见

不同的隔离级别实际上就是在创建视图数组的时机上的差别

在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图

在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。

当前读

MySql进行更新数据时,都是先读再写。此处的读是当前读,也就是读取记录的最新版本数据,然后再判断是否继续执行更新。比如:在表t(id,a)中有一条记录(1,2),先启动时事务a,然后启动事务b 进行更新 update t set a=3 where id=1 进行提交事务b,然后在事务a中执行 update t set a=3 where id=1 ,最后继续在事务a中查询select * t where id=1的数据。此处事务中会根据当前都匹配到(1,3)记录,但是innodb判断a的值已经是3 无需更新,因此最后的查询还是1,2。但是如果事务a中将a更新为4,那么会进行真正的更新。ps:不管是否真正执行更新操作,只要是update操作,那么都是获取行锁。

在更新操作中,MySQL的当前读会判断是否有必要进行更新,比如将等于4的字段a 执行set a=时并不会真正进行更新。但是不管是否真正更新操作,都会获取当前行的写锁。

事务开启方式

1 手动开启 begin、commit或者rollback

2 自动开启 设置mysql变量 autocommit =1开启,任何执行语句都会执行完后自动提交。autocommit =0关闭,执行语句执行后需要手动执行commit或者rollback,否则当前事务一直处于开启状态。

从上面得知,任何执行语句执行时都会开启事务,但是执行完之后是否自动提交取决于autocommit参数。因此,最佳实践方式是设置autocommit =1,单条语句执行后立刻提交。需要事务性处理多个语句时,通过begin、commit的方式手动开启事务。

手动事务与自动提交的关系如下:

1 begin transaction 后,不管autocommit 是1还是0 。 只有当commit数据才会生效,rollback后就会回滚。

2 当autocommit 为 0 时,不管有没有 begin transaction。 只有当commit数据才会生效,rollback后就会回滚。

3 如果autocommit 为1 ,并且没有begin transaction ,会自动commit。调用rollback是没有用的,即便设置了savepoint。

为什么避免长事务

1 事务期间,更新操作会保持写锁,直到提交为止。这会导致其他更新相同数据记录的操作堵塞。2 该事务一直未提交,即处于活跃状态,着系统里面会存在很老的事务视图。由于这些事务随时可能访问数据库里面的任何数据,所以这个事务提交之前,数据库里面可能用到的undolog都必须保留,这就会导致大量占用存储空间。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值