这两天在重构考试系统的时候,对数据库的锁,做了一下简单的学习,这里集锦一下数据库锁的零星知识。
锁的意义在于数据的安全、完整性和一致性,不做赘述。
为什么需要锁?
多个用户对数据库并发操作时,会带来数据不一致的问题,大致分为以下三种情况:
A:丢失更新
A、B两个用户对同一数据进行修改,其中B用户破坏了A用户的修改结果,这样在A用户的事物中,就会导致更新失败,如,订票系统。
B:脏读
A用户修改了数据,B读出此数据,可是A由于某些原因,恢复了原始数据,导致,B读出的数据不一致。
C:不可重复读
A用户读取数据,B用户修改了数据后,A再去读这个数据,前后比对,结果不一致,导致读数据失败。
锁的类型有哪些?
从数据库的角度,sql锁,分为独占锁、共享锁、更新锁。
共享锁:
允许多个事物同时读取一个数据资源(select),资源上有共享锁的时候,任何其他事物不能修改这个数据。
默认情况下,事物读取数据完毕后,自动释放共享锁,将事物的隔离级别设置为重复读和更高级别除外。
更新锁:
可以防止通常形式的死锁。通常模式下,两个事物都可以获得资源的共享锁,当两个事物都企图去更新同一资源的时候,都需要将共享锁,上升为排他锁,也就是企图去获得对方的资源,这样就造成了永久等待的后果,也就是死锁,为避免这种情况的发生可以使用,更新锁。
更新锁,之所以可以避免更新死锁,是因为,一次更新,只允许有一个事物获取该资源的更新锁,如果这个事物要更新数据,则更新锁转换为排它锁,否则转换为共享锁。
可见更新锁既解决了死锁,又保证了,在读取的时候不被更新,自动转化为共享锁模式。
排它锁:
只允许一个事物去修改某一资源,其他事物也不能读取该资源,可以防止,多事物的并发性,但是该锁,也禁止了其他事物读取该资源的权限。可谓有利也有弊。
另外,数据库还有意向锁,是说,sql有在资源的底层获取共享或独占锁的意向。包括意向共享、意向排他、意向排他共享。
意向排他共享锁,是允许其他事物读取顶层的共享锁数据,而在底层有独占资源的意向。
共享意向锁,是事物意图在底层资源上放置共享锁,其他事物可以读取数据;
独占意向锁,是事物意图在底层资源上放置排它锁,防止其他事物读取和修改数据;
意向锁,可以提高性能。
例如,放置在表级的共享意向锁表示事务打算在表中的页或行上放置共享锁。在表级设置意向锁可防止另一个事务随后在包含那一页的表上获取排它锁。意向锁可以提高性能,因为 SQL Server 仅在表级检查意向锁来确定事务是否可以安全地获取该表上的锁。而无须检查表中的每行或每页上的锁以确定事务是否可以锁定整个表。
程序员的角度,分为乐观锁和悲观锁。
乐观锁,完全依靠数据库来管理。
悲观锁,程序员自己管理数据或对象上的锁处理。
锁的粒度:
行、页、表、数据库,这些比较容易理解,而页、键、键范围和索引就不怎么理解了。
copy一下:
键 索引中的行锁。用于保护可串行事务中的键范围。
页 8 千字节 (KB) 的数据页或索引页。
扩展盘区 相邻的八个数据页或索引页构成的一组。
锁定的时间:
锁保持的时间长度是保护请求资源所需要的时间。
保护读取事物的共享锁的时间由事物的隔离级别确定。read commited,默认是在读取页的时间内,当扫描到一下页的数据获得锁后,才释放上一页的锁;如果将事物的隔离级别设置为重复读(repeatable read)或serializable或hold lock的时候,锁定时间到事物结束时间。
排它锁,用于保护更新,锁定时间为事物结束。
冲突锁,等待到冲突解决;
如果没有设置连接超时,锁定时间有可能会无限等待。
游标的锁定时间,不懂。
可以使用set_dealockpriorty来自定义,发生死锁时的解决办法。