一、从策略上分:乐观锁、悲观锁
乐观锁:每次去读数据都认为其它事务没有在写数据,所以就不上锁,快乐的读取数据,而只在提交数据的时候判断其它事务是否搞过这个数据了,如果搞过就rollback。乐观锁相当于一种检测冲突的手段,可通过为记录添加版本或添加时间戳来实现。
悲观锁:每次读数据的时候都会上锁,直到取出数据。悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性,但随之而来的是各种开销。悲观锁相当于一种避免冲突的手段。
二、从读写角度上分:共享锁、排它锁
共享锁(S锁,Shared Lock):也叫读锁(Read Lock),持有S锁的事务只读不可写。如果事务A对数据D加上S锁后,其它事务只能对D加上S锁而不能加X锁。
排它锁(X锁,Exclusive Lock):也叫写锁(Write Lock),持有X锁的事务可读可写。如果事务A对数据D加上X锁后,其它事务不能再对D加任何锁,直到A对D的锁解除。
三、从粒度上分:表级锁、行级锁
表级锁(Table Lock):表级锁将整个表加锁,性能开销最小。用户可以同时进行读操作。当一个用户对表进行写操作时,用户可以获得一个写锁,写锁禁止其他的用户读写操作。写锁比读锁的优先级更高,即使有读操作已排在队列中,一个被申请的写锁仍可以排在所队列的前列。
行级锁(Row Lock):行级锁仅对指定的记录进行加锁,这样其它进程可以对同一个表中的其它记录进行读写操作。行级锁粒度最小,开销大,能够支持高并发,可能会出现死锁。
四、总结
1、表级只有共享锁没有排它锁,排它锁用于行级
2、加了共享锁可以继续加共享锁,不能加排它锁,加了排它锁后,不能再加任何锁
3、DML语句,对操作的行加排他锁,对整个表u加共享锁
4、对于DDL语句,全表加排他锁
如果执行insert、update、delete、select .... for update语句,表上共享锁,对应的数据行上会加行级排它锁。该表不能执行ddl语句,对应的数据行不能执行update、delete(因为排它锁会阻塞,直到锁释放),可以执行select语句,其他行数
————————————————————————————————————
数据库DQL、DML、DDL、DCL简介
1、数据库查询语言DQL:select ...from...where
2、数据库操作语言DML:insert、update、delete
3、数据库定义语言DDL:create table、view、index、cluster、syn等。DDL是隐形提交,不能rollback
4、数据控制语言DCL:GRANT授权、ROLLBACK 回滚、COMMIT 提交
————————————————————————————————————
死锁分析与解决
一、事务之间对资源交替访问
出现原因:
一个用户A 访问表A(锁住了表A),然后又访问表B;另一个用户B 访问表B(锁住了表B),然后企图访问表A;这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B才能继续,同样用户B要等用户A释放表A才能继续,这就死锁就产生了。
解决方法:
这种死锁比较常见,是由于程序的BUG产生的,除了调整的程序的逻辑没有其它的办法。仔细分析程序的逻辑,对于数据库的多表操作时,尽量按照相同的顺序进行处理,尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源。
二、并发修改同一记录
出现原因:
用户A查询一条纪录,然后修改该条纪录;这时用户B修改该条纪录,这时用户A的事务里锁的性质由查询的共享锁企图上升到独占锁,而用户B里的独占锁由于A有共享锁存在所以必须等A释放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。
解决方法:
1. 使用乐观锁进行控制。
2.使用悲观锁进行控制
三、索引不当导致全表扫描
出现原因:
如果在事务中执行了一条不满足条件的语句,执行全表扫描,把行级锁上升为表级锁,多个这样的事务执行后,就很容易产生死锁和阻塞。类似的情况还有当表中的数据量非常庞大而索引建的过少或不合适的时候,使得经常发生全表扫描,最终应用系统会越来越慢,最终发生阻塞或死锁。
解决方法:
SQL语句中不要使用太复杂的关联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,建立相应的索引进行优化。