一、锁机制的作用
并发事务访问同一资源,可能会导致数据不一致。锁机制将访问顺序化,保证数据的一致性。
二、事务的四大特性:ACID
原子性 (Atomicity)
一个事务的所有操作,全做or不做,不会结束在某个环节
一致性 (Consistency)
事务开始前和结束后,数据库都保持完整性
隔离性(Isolation)
多个并发事务同时读写数据,互不干扰。防止多事务并发时出现交叉执行导致数据的不一致
持久性(Durability)
事务对数据的修改是永久的,即使系统故障也不会丢失
三、
悲观锁:(数据库实现)
比较悲观,每次读取时,都认为别人(线程)要修改,所以会上锁。别人(线程)不能读取,只能等待其释放。
悲观锁的两种不同实现:
A. 共享锁
对多个不同的事务,对同一个资源,共享同一个锁。(一个门有多把钥匙)
mysql中在执行语句后面加lock in share mode命令
B. 排他锁
对多个不同的事务,对同一个资源,只能有同一个锁。
mysql中在执行语句后面加for update命令
关系型数据库中的锁(操作前就上锁)
1. 行锁:给某一行(记录)加锁。例如,select .... for update,select挑选出的结果行锁住,事务提交或回滚之前,不允许其他事务对其更新删除等操作。
2. 表锁:给某个表加锁。
3. 读锁:
4. 写锁:
优点: 适用于写多读少,冲突比较严重的系统
缺点:耗时长
乐观锁:(自己实现)
比较乐观,每次去拿数据,都认为别人不会修改,所以不会上锁,可以被其他线程读取,但是在更新时会判断数据是否在被自己读取和更新期间被别的线程更新,被更新过则更新失败,否则更新成功。
优点: 适用于读多写少,冲突很少,减少锁的开销,提高吞吐量
版本号机制
表中增加一个版本号字段(数据被修改次数),更新前读取数据获得版本号,提交更新时将其作为where子句进行更新,若在获得版本号和更新期间版本号被其他线程更新了(不是获得的版本号),则更新0条,表示失败。否则更新成功(版本号+1)。更新失败会再读取数据(此时是新的版本号)尝试更新。
update table set x=x+1, version=version+1 where id=#{id} and version=#{version};
CAS操作
数据所在内存值、预期值、新值
更新时若当前内存值与之前取到的值相等则用新值更新,失败则重试。自旋操作,不断重试。