Mysql事务原理与锁机制

Mysql事务原理与锁机制

参考文章:https://lish98.blog.youkuaiyun.com/article/details/124130816

查看当前事务隔离级别

//查看当前事物级别:
SELECT @@tx_isolation;

设置 mysql 事务隔离级别

//设置read uncommitted级别:

set session transaction isolation level read uncommitted;

 

//设置read committed级别:

set session transaction isolation level read committed;

 

//设置repeatable read级别:

set session transaction isolation level repeatable read;

 

//设置serializable级别:

set session transaction isolation level serializable;

mysql 的事务隔离级别

  • read uncommitted 读未提交

    set session transaction isolation level read uncommitted;
    
    BEGIN;
    UPDATE user_balance SET balance = balance + 500 WHERE id = 1;
    
set session transaction isolation level read uncommitted;

BEGIN;
SELECT * FROM user_balance WHERE id = 1

最终读取到未提交的数据(脏读)

  • read committed 读已提交,

    • 解决了脏读问题,存在不可重复读问题

  • repeatable read 可重复读

    • 解决可重复读问题

可重复读时,还未提交事务,
在这里插入图片描述

先修改[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gTLZCfYE-1661406405369)(C:/Users/zrx15/AppData/Roaming/Typora/typora-user-images/image-20220822175448632.png)]

lisi 的balance为5000(事务开启前是10000),

再从事务中查询 lisi 的balance ,结果仍然是10000在这里插入图片描述

  • 存在幻读问题

串行化: 可以解决以上所有问题(个人理解:不存在并发,不就没有并发问题了嘛)

事务是如何实现的

  • 事务的 隔离性锁机制 实现。

  • 而事务的原子性、一致性和持久性由事务的 redo 日志undo 日志来保证。

  • REDO LOG 称为重做日志,提供再写入操作,恢复提交事务修改的页操作,用来保证事务的持久性

  • UNDO LOG 称为回滚日志,回滚行记录到某个特定版本,用来保证事务的原子性、一致性

undo log

用来保证事务的原子性、一致性

类似写时复制

在这里插入图片描述

解释:当有多个调用者请求同一个资源时,调用者都会获得同一个初始资源,其中有调用者请求修改资源时,系统会复制一个模板资源,供该调用者修改,此时,其他调用者读取到的仍然是初始资源

undo log也是类似,当 mysql 进行 INSERT、UPDATE、DELETE时,回滚时都会分别执行一次 DELETE、UPDATE、INSERT,而mysql为了记录这些回滚的内容就引入的 undo logSELECT 查询不会记录到 undo log 中(毕竟不会修改数据)

undo log的作用

原文:https://blog.youkuaiyun.com/qq_36389060/article/details/124130816

回滚数据

会有人对undo日志有误解:undo用于将数据库物理的回滚到语句执行之前或事务之前的样子而事实是,undo是逻辑日志,因此只是将数据库逻辑地恢复到之前的样子,该事务中所有的修改语句都被取消,但是数据结构和页本身在回滚之后可能大不相同(应该是其他事务完成了commit成功修改了其他数据)

比如:一个事务在修改当前一个页的某几条数据,同时也有其他事务也在修改同一页另外几条数据,因此,不能将改页回滚到事务开始时的状态,会对其他事务的工作造成影响

MVCC(记录版本链)

undo的另一个作用是MVCC,即在innoDB存储引擎中MVCC的实现是通过undo来完成。当用户读取一行记录时,若该记录已经被其他事务占用,当前事务可以通过hdo读取之前的行版本信息,以此实现非锁定读取。解决读写同时高并发

以上三个隔离级别(除了串行化)都存在脏写问题(非常严重)

举个栗子:我们通过java读取到数据库中的值为 500,然后我们通过java将其减少 200 ,结果为 300 提交给数据库,此时,就可能会出现脏写问题,注意,我们是抽出数据来操作后再返回给数据库,而数据库中该条数据可能已经发生了改变(比如在修改的时候恰好变成了800),那么我们提交的时候,这个800就会被改为300,这样就出现了脏写问题

其一解决方法: 不要在java(数据库外)更新数据库里面的数据,利用mysql的行级锁,可以用 update语句进行修 update account set balance=balance -200 where id 1;

面试题:查询操作方法需要使用事务吗

(rr,可重复读)需要加 读事务,readonly = true(spring中的)

举个栗子:

在这里插入图片描述

select * from user_balance where id = 1 ,查询出zhangsan的balance为 400,此时,我们将lisi的balance由5000改为 10000,而如果我们加了事务,我们执行select * from user_balance where id = 2查询出的lisi的balance仍然是原来的 5000,如果不加,查出来的就是10000

也就是加了事务,那么我们查出来的几个数据肯定是出自同一个时间点

如果查询操作较多的系统,采用 repeatable read 可重复读,因为可能要不断生成报表

而对并发要求高的 则采用 read commit 读已提交,没有什么报表,rc 读操作可以不加事务,那么性能会更高

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值