# 锁 ## 乐观锁 ### 概念 ```text 乐观锁不是数据库自带的,需要我们自己去实现。乐观锁是指操作数据库时(更新操作),想法很乐观,认为这次的操作不会导致冲突,在操作数据时,并不进行任何其他的特殊处理(也就是不加锁),而在进行更新后,再去判断是否有冲突了。 ``` ### 实现 使用数据版本(Version)记录机制实现,这是乐观锁最常用的一种实现方式。何谓数据版本?即为数据增加一个版本标识,一般是通过为数据库表增加一个数字类型的 “version” 字段来实现。当读取数据时,将version字段的值一同读出,数据每更新一次,对此version值加一。当我们提交更新的时候,判断数据库表对应记录的当前版本信息与第一次取出来的version值进行比对,如果数据库表当前版本号与第一次取出来的version值相等,则予以更新,否则认为是过期数据 1. 数据库表设计 account 表有三个字段,分别是id,user_id,amount 2. 实现 > 1. 先读account账户表某个人的数据,得到amount的金额数为amountValue > 2. 每次更新account表中的amount字段时,为了防止发生冲突或资金问题,需要这样操作 ```mysql update account set amount = newValue where amount = amountValue; ``` 只有这条语句执行了,才表明本次更新amount字段的值成功 比如买家账户金额只有10块钱,分别从app 和 PC 同一时间进行支付操作,利用这个乐观锁机制,第一笔订单更新后成功了,第二笔却无法成功,这样就防止了扣除资金问题发生。 ## 悲观锁 ### 概念 ```text 与乐观锁相对应的就是悲观锁了。悲观锁就是在操作数据时,认为此操作会出现数据冲突,所以在进行每次操作时都要通过获取锁才能进行对相同数据的操作,这点跟java中的synchronized很相似,所以悲观锁需要耗费较多的时间。另外与乐观锁相对应的,悲观锁是由数据库自己实现了的,要用的时候,我们直接调用数据库的相关语句就可以了。 ``` ### 实现 说到这里,由悲观锁涉及到的另外两个锁概念就出来了,它们就是共享锁与排它锁。共享锁和排它锁是悲观锁的不同的实现,它俩都属于悲观锁的范畴。 ### 共享锁 #### 概念 ```text 共享锁指的就是对于多个不同的事务,对同一个资源共享同一个锁。 ``` #### 实现 ```text select * from test where id = 1 lock in share mode ``` ### 排它锁 #### 概念 ```text 排它锁与共享锁相对应,就是指对于多个不同的事务,对同一个资源只能有一把锁。 ``` #### 实现 ```text select * from test where id = 1 for update ``` ## 行锁 行锁,由字面意思理解,就是给某一行加上锁,也就是一条记录加上锁。 ## 表锁 MyISAM常有,行锁如果where条件辨识度低也会升级成为表锁 ## 相关文章 [MySQL 避免行锁升级为表锁——使用高效的索引](https://www.cnblogs.com/zyy1688/p/9983122.html) [MySQL事务隔离级别](https://blog.csdn.net/JIESA/article/details/51317164) [Innodb中的事务隔离级别和锁的关系](https://tech.meituan.com/2014/08/20/innodb-lock.html) [数据库事务隔离级别、锁机制](https://www.jianshu.com/p/faba8a3a6d67)