数据库中的锁
锁的重要性
多用户同时访问一个数据资源,如果没有锁的管控则会导致如下情况的发生:
修改丢失
多个用户同时操作,导致数据被覆盖
不可重复读
数据被覆盖了,所以比如刚刚的查询结果,下次可能就无法查询出来。
脏读
读取了部分更新不完整的数据
举个例子: update tableName set xx=”you” xm=1 其中xx的值已更新,而xm还未更新,数据就被读取了,既不是更新后的有用数据,也不是
未更新前的正确数据,这种数据毫无意义。
幻读
某一瞬间读取的时候有某条数据,再次读取时就没有了
锁的作用
保证访问同一资源时,有个先后顺序管理,处理并发问题
锁的分类
1.乐观锁
认为没有并发,读取数据---更新---保存//实际上就是没有锁
乐观锁保存数据的处理方式
但并发是真实存在的,乐观锁会通过如下几种方式来保证,数据可以保存
1时间戳
在数据库增加一列(long类型),每次查询时拿出来,更新时加1,保存时判断是否大于数据库的值
乐观锁的实现要保证任何操作都按照这个规范,所以也有个漏洞,其他渠道的更新会导致无法判断
乐观锁的好处是 性能高,因为乐观锁实际上是用程序进行控制的!!!!
2.悲观锁
认为任何时候都可能多线程并发,读取数据时恰巧在修改数据,悲观锁是基于数据库的机制来完成的
共享锁S锁 读锁,允许别的事务来读,但是不允许修改,读完就释放,锁定数据页;除非holdlock就一直锁定
Holdlock 语法 select * from TableName with (Holdlock)
排他锁 X锁 写锁: 准备写数据,不允许读,也不允许写
更新锁 U锁 :先查询再更新
行锁 锁定某一行,比如:select * from tableName where id=1
表锁 锁定某一张表,比如: select * from tableName where 1=1
怎么避免死锁
其实在高并发时,死锁是无法避免的,只能去减少死锁的可能
- 不用锁就不会锁,乐观锁
- 同一操作顺序,先A再B再C
- 最小单元锁,锁里面的操作尽量减少
- 避免事务中等待用户输入
- 减少数据库并发
- 分库分区分表
- 降低事务等级
- 设置死锁时间 set lock_timeout(锁超时时间)