本文共 1531 字,大约阅读时间需要 5 分钟。
事务是必须满足4个条件(ACID):
- 原子性(Atomicity,或称不可分割性)
- 一致性(Consistency)
- 隔离性(Isolation,又称独立性)
- 持久性(Durability)
一句话概括就是,事务中所有的DML,要么全部成功,要么全部失败
事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
---|---|---|---|
读未提交(read-uncommitted) | 是 | 是 | 是 |
读已提交(read-committed) | 否 | 是 | 是 |
可重复读(repeatable-read) | 否 | 否 | 是 |
串行化(serializable) | 否 | 否 | 否 |
注意: 读已提交很多人叫他不可重复读,其实字面意思就是读已提交,很明显就是当前事务可以读取到其他事务已经提交的内容,比如乐观锁,必须使用这种方式
- 表锁
- 页锁
- 行锁
- 排他锁
- 共享锁
很多人将事务和锁搞混,首先事务只是避免如果当前事务中某一个DML出错,导致的一致性错误,和锁其实没有什么关系
- 举个例子 看下面的伪代码 begin user1Money = “select money from user where id=1;” if user1Money>10 update user set money = money-10 where id = 1; todo something 代码出错 update user set money = money+10 where id = 2; commit; 出错rollback; 如果出错,那么事务是不会真正修改这2个用户的金额 但是这和锁没有任何关系,如果并发执行,2条线程当前都检查到用户1的金额确实>10,但是线程1先完成了,但是线程2突然被挂起了,还在等CPU的时间片段 目前用户1金额是0了。 线程2恢复,继续执行,成功-> 用户1金额成了-10. 这并不是我们想要的结果 所以会用到锁的机制
- 乐观锁的方式 隔离级别必须为Read-Commited: begin while(conditionVariable) select version from user where id=1; if user1Money>10 update user set money = money-10,version=version +1 where id = 1 and version = version; 如果update 影响行数为1 让条件变量失效 todo something update user set money = money+10 where id = 2; commit; 代码中途出错rollback;
版本控制来进行不断尝试,如果当前用户被其他线程改过,那么进行重试
- 悲观锁 InnoDB 当select 使用for update时会进行行锁,前提是where条件必须是索引 begin user1Money = "select money from user where id=1 for update;" if user1Money>10 update user set money = money-10 where id = 1; todo something update user set money = money+10 where id = 2; commit; 代码中途出错rollback;
简单说一下乐观锁和悲观锁的应用场景:
如果修改的数据并发非常高,那么建议使用悲观锁,性能会比乐观锁好很多 如果修改数据的并发不是很高,那么建议使用乐观锁
转载地址:http://qtlsi.baihongyu.com/