透过以下两个命令,我们还能看到整个数据库的锁定和阻塞详细信息:
SELECT * FROM sys.dm_tran_locks EXEC sp_lock |
图 4 session id = 52 的 process 因阻塞而一直处于等待中 (WAIT)
另透过 KILL 命令,可直接杀掉造成阻塞的 process,如下:
KILL 53
-------------------------------------------------------------------------------------------
欲解决无限期等待的问题,除了前述的 SET LOCK_TIMEOUT 命令外,还有更省事的做法,如下,在会话 B 的 SQL 语句中,在表名称后面加上 WITH (NOLOCK) 关键字,表示要求 SQL Server,不必去考虑这个表的锁定状态为何,因此也可减少「死锁 (dead lock)」发生的机率。但 WITH (NOLOCK) 不适用 INSERT、UPDATE、DELETE。
SELECT * FROM Orders WITH (NOLOCK) WHERE OrderID=10248 |
类似的功能,也可如下,在 SQL 语句前,先设置「事务隔离级别」为可「脏读 (dirty read)」。
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED SELECT * FROM Orders WHERE OrderID=10248 |
两种做法的效果类似,让会话 B 即使读到被锁阻塞的记录,也永远不必等待,但可能读到别人未提交的数据。虽然说这种做法让会话 B 不用请求共享锁,亦即永远不会和其他事务发生冲突,但应考虑项目开发实际的需求,若是会话 B 要查询的是原物料的库存量,或银行系统的关键数据,就不适合用这种做法,而应改用第一种做法的 SET LOCK_TIMEOUT 命令,明确让数据库抛回等候逾时的错误代号 1222,再自己写代码做处理。