mysql事务和锁
尝试进行归纳总结事务和锁的一些思考.
数据库是什么? 保存数据的地方.
为什么保存数据要用数据库呢? 我直接把数据放文件里, 不也一样吗? 比如我自己序列化json文件保存成txt文件成不? 也行, 但是就不方便检索, 之类的.
数据库就方便检索了呀, 数据库相比文件系统有4个特点:
- A - 原子性
- C - 一致性
- I - 隔离性
- D - 持久性
这里只说锁, 锁是用来保证隔离性的.
隔离性是啥?
比如, 我现在自己实现了一个不怎么完善的数据库, 只是按SQL标准实现了增删改查等命令, 但是操作的数据是直接落实到系统的文件上的. 同时, 要知道SQL标准也规定了4种数据库事务隔离级别, 别急, 我们这个不完善的数据库没有实现事务隔离级别, 也没有实现任何锁, 仅仅是我们知道有这么个东西而已, 暂时不打算去实现它^_^
虽然我们没有实现它, 但还是可以从事务的角度来进行一下思考, 也就是说我们假想事务这么个东西, 可以启动事务, 提交事务和回滚事务.
假设两个事务--A, B, 说明以下几种存在的问题:
- 脏读 - A事务启动, 先读取一行, 值为1, 还没提交, B事务启动, 修改了A刚刚读取的那一行, 修改为2, 注意, 没有锁, 虽然在我们的想像中, B还没有提交, 但是anyway, B就是直接就把修改写到文件里了, 然后A再读取这一行, 值是2. 这叫做A事务读取到了B事务还没提交的数据, 是为脏读.
- 不可重复读 - A事务启动, 先读取一行, 值为1, 还没提交, B事务启动, 还是把A读取的一行修改为2, 注意, 接下来B提交了, 嘿嘿, 刚刚B没提交, 这下B提交了, 是不是没问题了? No way!! 不管怎样, B还是把2写到文件里了, 然后A再读取这一行, 值是2. 这叫做A事务的两次对同一记录读取到了不同值, 是为不可重复读.
- 幻读 - A事务启动, 读取值小于2的, 假设现在就一条, B事务启动, 插入了一条值为1的, 不管提交不提交, A事务再去读取值小于2的记录, 就会发现有两条了. 是为幻读, 怎么我出现幻觉了吗? 刚刚还是一个呢, 现在怎么变成俩了??
- 丢失更新 - 不说了
锁和MVCC主要就是用来解决以上几个问题的, 如何解决? 且听下回分解.
MVCC - 多版本并发控制, 仅仅是为是在RC和RR级别中普通的Select操作时不加锁, 提高并发性能用.
幻读的解决, 首先要使用RR级别, 并且开启gap lock, 也就是innodb_locks_unsafe_for_binlog设置为0, 若为1表示使用不安全的binlog, 也就是表示不使用gap lock, 换言之, gap lock在一定程度上是保护了安全的binlog的, 即保证主从上数据的一致性. 其次, 还要在所有Select语句后加上 lock in share mode或者for update, 用来显式的加锁.