mysql 事务隔离级别与锁机制

2021/10/31 19:12:09

本文主要是介绍mysql 事务隔离级别与锁机制,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

事务

        什么是事务?

        事务是将一系列sql语句组合成一个逻辑处理单元,那么这一系列得sql语句需要满足事务的ACID属性

        1.原子性(因为事务是组合在一起的,期望应该是同时执行,要么全成功,要么都不成功)

        2.一致性(事务开始到结束数据值一致,如开始获取a为1,在修改之前不能变成其他值,否则不满足事务一致性)

        3.隔离性(事务操作期间内部数据对于外部是不可见的,不受外部影响)

        4.持久性(事务的数据提交后,对数据改变是永久的)

        为什么要使用事务?

        业务情况决定,保证操作的原子性比如:

经典业务场景转账:a  转账给 b  1000元

        1.a判断有没有1000余额  

        2.a的余额-1000

        3.b的余额增加1000,转账完成

问题:

        如果 第二步完成了,第三步发现b的卡注销了,首先转账没有完成,但是a的钱已经被扣掉了

解决办法就是使用事务:

        将整个转账的业务写成一个整体,所有操作成功才算完成,然后提交事务,其中一步出错全部回退所有操作

使用事务的问题

        如果只是单个操作,那么上面那个问题其实就完成了,但是如果多线操作(并发)会出现那些问题呢?

        脏写:事务之间相互隔离,同时操作同一行,结果覆盖

                如:两个事务同时去获取a的余额(5000),一个是转账1000出去,一个转账500出去

                第一个事务-1000 剩4000,操作完成,第二个事务-500 剩4500,操作完成,结果是

                4500,明显不是我们要的结果,称为脏写

        脏读:b事务读取a事务未提交的数据称为脏读

                 如:a事务给a账号-1000,但是还没有提交内容,b事务获取到了4000去做对应操作

                a事务发现操作有误,回滚了事务,那么b读到的就是脏数据

        不可重复读:相同语句查询到不同内容

                如:a事务开始查询a账号5000,此时b事务读取并且很快修改了a的余额为4000.

                a事务操作比较慢,修改之前再查询了一下余额,发现两个不一致了,此为不可重复读

        幻读:a事务读取到b事务提交了的新数据

                幻读感觉上和脏读有点类似,用例子来区分下:

                还是a事务,读取a账户的交易记录,第一次默认查7天交易记录,10条。此时b事务

                a的老婆用银行卡刷了两条购物出来,而且交易完成,事务提交。然后a又查询了一下,

                发现多了两条交易出来,同样查询7天记录,跟出现幻觉一样多了两条,称为幻读

        ps:以上所有情况都指的是在事务中的情况,就是开启了begin然后做的操作

事务隔离级别

        有问题就需要处理

        数据为了处理以上问题,就出现了事务隔离级别:

 以上四种隔离级别就是数据库提供给我们处理上述问题的,隔离级别越高,并发的影响就越小,但是相应的代价就越大

首先我们来看下关于mysql事务隔离级别的设置:

        查看当前级别:show variables like 'tx_isolation'

                        

        设置事务隔离级别:set tx_isolation='READ-COMMITTED'   

                上图隔离级别的四个  READ-UNCOMMITTED,READ-COMMITTED

                                                  REPEATABLE-READ,SERIALIZABLE

        PS:mysql 默认是可重复读

        

读未提交:a事务读取到b事务未提交的数据

读已提交:a事务读取到b事务提交的事务(满足同一事务中业务数据不要随意变动)

可重复读:a事务读取不到b事务提交的数据,但是能够在更新时感知数据。默认

        间隙锁:只在可重复读有效,范围内的值都会加锁(某种程度上可以解决幻读问题)

        临键锁:行锁与间隙锁的组合

可串行化:select也会加锁,其他事务无法操作,没有并发问题,但是效率极低

        锁是用来协调多个进程或者线程,并发操作同一资源的一种机制,用来保证并发情况下数据不出现问题。

        锁的分类:

                悲观锁和乐观锁

                        乐观锁:      开始事务认为没有竞争,更新的时候才去做校验,成功则提交,失败则回滚,实际操作一般用版本控制,如开始获取数据为第一版,后续更新如果版本不变则成功提交,如果版本改变表示被其他操作了,重新获取数据再走业务

                        悲观锁:    开始事务直接锁定数据,不让其他人操作,完成后再释放

                读锁和写锁(都属于悲观锁)

                        读锁(共享锁):针对同一数据,多个读操作同时进行互不影响

                        写锁(排他锁):当前写操作未完成,阻断其他写锁与读锁

                表锁与行锁

                        字面理解,一个锁表,一个锁行数据

                区别:

                        表锁加锁快,开销小,不会死锁,并发低,一般表迁移用

                        行锁加锁慢,开销大,会死锁(a获取b,b获取a,相互获取不到,等待,就死锁了)并发度高

                        Myisam 数据库引擎一般是表锁,不支持行锁与事务

                        InnoDB 数据库引擎支持行锁与事务

        总结:

                mylsam在执行增删改查时都会加对应读锁或写锁

                innoDB查询不加锁(不是串行化隔离级别),更新会加行锁

                innerDB的行锁是针对索引加的,不是针对数据,如果索引失效,行锁会升级为表锁

锁优化的建议:

        1.尽可能让数据检索都通过索引,避免行锁升级

        2.合理设计索引,尽量缩小锁的范围

        3.减少条件范围。避免间隙锁

        4.控制事务大小,减少锁定的资源与时间,加锁的sql能放事务的后面

        5.低级别的事务隔离(减少表的锁定)



这篇关于mysql 事务隔离级别与锁机制的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程