数据库

位置:IT落伍者 >> 数据库 >> 浏览文章

SQL7中LOCK的理解(2)


发布日期:2022年10月03日
 
SQL7中LOCK的理解(2)

下面介绍的是锁的并发问题和解决方法

在实际情况中通常会因为lock发生四中情况

下面用个定座系统举例所有的语句都工作在默认隔离级别下

丢失的更新

user run

begin tran

select 空座位 得到

update 定座位

commit

如果user在user update之前运行同样的程序都会得到空座位是的信息当然user也可以定座位结果就是user的定座是最终有效的user的定座被覆盖为了避免这种情况看看用隔离级别能不能解决这四种隔离级别最多在表上施加S由于S是兼容的因此user照样能得到空座位是的信息丢失的更新也照样会发生SQL提供了表级锁定选项TABLOCKX能避免这种情况的发生但丧失了并发

髒读

user run

begin tran

update row A

commit

如果user能在user update的同时读出表中的数据(包含 row A) 那么就产生了髒读因为user可能commit也可能rollbackupdate并没有被确认默认情况下是不会产生髒读的因为update将产生行的X表的IX而表IX和S是不兼容的那么在什么情况下我们需要髒读呢如果我们不需要确切的数据我们需要的是一个大概的趋势个别数据的不确定没有关系想想一个股票系统同一时刻的改写会很多也就是表上会有许多IX锁如果我们需要查询表获得大致情况那么只有等改写结束为了提高并发此时我们需要髒读解决方法就是在user的会话环境中设置事务隔离级别为read uncommitted

不可重复读

user run

begin tran

select tab where

select tab where

commit

当user在交易中执行两次select所得到的结果不一样这便是不可重复读发生的原因是user在user第二次select之前对tab做了修改select语句虽然对表有读锁但在默认情况下读锁在select语句执行完就被释放而不是保持到交易结束为了避免不可重复读的发生只要select产生的锁保持到交易结束就可以了将user的会话环境中设置事务隔离级别为repeatable read

幻影

user run

begin tran

select tab where

select tab where

commit

虽然将user的会话环境中设置事务隔离级别为repeatable read但当user在交易中执行两次select所得到的结果还会不一样这便是幻影因为user仅仅将select出来的行加了S锁但user可以insert满足where条件的新行使得两次select的结果不一样解决方法是将user的会话环境中设置事务隔离级别为serializable或者在表级锁定选项中选holdlock

锁定超时

前面说过当某个语句因为锁而不能立即执行时会等待直到锁被释放但如果持有锁的语句执行时间过长(未优化)那么就会等待过长影响响应因此我们通过lock_timeout来将等待过长的语句rollback需要注意的是当数据量增加时可能发生不希望的lock_timeout原因是SQL需要更多的时间来处理数据为此我们也需要适当的增加lock_timeout

索引在锁中的应用

大家都知道索引可以提高查询速度其实索引还有一个很重要的功能就是提高并发

当user run update tab set col=xxx时user对tab run select * from tab将会等待直到user执行完但如果user执行select * from tab where col<>xxx也就是user要查询的行并不是user改写的行结果如何呢?同样user也要等到user执行完这样就没有什么并发可言如果我们在col上建立index就可以让user无须等待立即执行更常用的是父表和子表的情况通常为了保证引用完整性SQL在修改数据时都会将依赖表加锁但如果有index情况就好的多

上一篇:关于日期的sql 做报表的时候可能有用

下一篇:数据库手边系列:SQL Server数据表信息