Mysql 一致性
关系型数据库的一致性
3种读
脏读
一个事务读取到另一个事务未提交的数据
不可重复读
不可重复读的重点是修改;同样的条件,
第1次和第2次读取id相同的记录,值却不一样。
幻读
幻读的重点在于新增或者删除;同样的条件, 第1次和第2次查出的记录数不一样
不可重复读解决
对于前者, 只需要锁住满足条件的记录
select * from user where userid=111 LOCK IN SHARE MODE; ;
对于幻读, 锁住条件依然无效
比如select * from user where enable=1 for update
此时别的事务 新增 了一条enable=1的记录
再次执行select ...for update时,幻读还存在
快照读(普通的select 无幻读问题)
幻读解决方案
https://blog.csdn.net/nandao158/article/details/116007366
4种隔离级别
以上三种问题,将隔离级别划分为四种。
- read uncommited 未提交读
- 会有脏读
- read commited 已提交读
- 无脏读问题 (oracle默认隔离级别)
- repeatable read 可重复读
- 无不可重复读问题。 (mysql 默认隔离级别)
- serializable 序列化
- 无幻读问题 。SERIALIZABLE会在读取的每一行数据上加锁
共享锁和排它锁
MySQL数据库的锁,按照作用范围划分为: 行级锁、页级锁和表级锁
行级锁又分为共享锁和排他锁两种
共享锁、读锁
select ...lock in share mode 其他事务可读不可改。
排它锁、写锁、独占锁
select ...for update 其他事务不可读
insert /delete/update
使用场景
订单的商品数量
如果是同一张表的应用场景,举个例子,电商系统中计算一种商品的剩余数量,在产生订单之前需要确认商品数量>=1,产生订单之后应该将商品数量减1。
1 select amount from product where product_id=1;
2 update product set amount=amount-1 where product_id=1 ;
如果1查询出amount为1,但是这时正好其他session也买了该商品并产生了订单,那么amount就变成了0,那么这时第二步再执行就有问题。
那么采用lock in share mode可行吗,也是不合理的,因为两个session同时锁定该行记录时,这时两个session再update时必然会产生死锁导致事务回滚。
总结:
lock in share mode适用于两张表存在业务关系时的一致性要求,for update适用于操作同一张表时的一致性要求。
MVCC
(Multiversion Concurrency Control)多版本并发控制
如何解决加锁后的性能问题的?
答案就是,MVCC多版本并发控制!它实现读取数据不用加锁,可以让读取数据同时修改。修改数据时同时可读取。
、
、