锁是事务获取的一种控制资源,用于保护数据资源,防止其它事务对数据进行冲突的或不兼容的访问。我们目前只要学习两种基本的锁模式就可以,它们分别是共享锁和排他锁。
共享锁主要是在读操作时使用,读操作一旦完成,数据库就会立即释放资源上的共享锁,而且多个事务可以同时持有同一数据资源上的共享锁。而排他锁主要是在修改数据时使用,一旦授予,事务将一直持有排他锁,直到事务完成(提交或回滚)。对于同一数据资源,如果有其他事务已经获取了该资源的任何类型的锁,就不能再获取该资源的排他锁,如果有其他事务已经获得了该资源的排他锁,就不能再获取该资源的任何类型的锁。
下面用一个示例来对其进行演示。首先开启一个会话 Connection 1,打开一个事务,对Production.Products表的一行进行更新,为产品2的当前单价19.00增加1.00,为了修改这一行,会话必须先获得一个排他锁。如下代码。
USE TSQLFundamentals2008; GO -- Connection 1,修改數據獲取排他鎖 BEGIN TRAN --開啟事務,但沒有commit,所以該會話會一直持有排他鎖 UPDATE Production.Products SET unitprice+=1.00 WHERE productid=2;
因为这个事务没有完成(没有提交或回滚),所以该会话会一直持有排他锁。此时再开启一个会话Connection 2,试图去查询这一行数据,为了读操作这个会话需要一个共享锁,但是这一行已经被前面那个会话的排他锁锁定,而且共享锁和排他锁是不兼容的,所以会话Connection 2会被阻塞,进入等待状态。如下代码。
USE TSQLFundamentals2008; GO -- Connection 2,查詢數據獲取共享鎖 -- 因為這一行已經被會話Connection 1所持有的排他鎖鎖定,而排他鎖和共享鎖是不兼容的,所以該會話會被阻塞 SELECT * FROM Production.Products WHERE productid=2;
如果发生了这样的锁定和阻塞,我们就会想办法去分析和排除这种阻塞,为此,我们可以通过一些动态管理对象来得到关于锁的详细信息。如下代码。
USE TSQLFundamentals2008; GO -- Connection 3 -- 1,通過動態管理視圖sys.dm_tran_locks查看該數據庫阻塞鏈中進程的信息 SELECT request_session_id AS spid, --會話ID resource_type AS restype, -- 資源類型 resource_database_id AS dbid, --數據庫ID DB_NAME(resource_database_id) AS dbname, --數據庫名稱 resource_description AS res,--資源描述 resource_associated_entity_id AS resid,-- 資源相關聯實體的ID request_mode AS mode,--鎖模式 request_status AS STATUS --鎖狀態 FROM sys.dm_tran_locks; -- 2,通過動態管理視圖sys.dm_exec_connections查看阻塞鏈中進程關聯的聯接信息 -- 比如联接建立的时间,最后一次发生读操作和写操作的时间以及最后执行的SQL代码 SELECT session_id AS spid, connect_time AS connecttime, last_read, last_write, text FROM sys.dm_exec_connections CROSS APPLY sys.dm_exec_sql_text(most_recent_sql_handle) AS ST WHERE session_id IN(52,54); -- 3,通过动态管理视图sys.dm_exec_sessions找到更多有用的信息 -- 包括登录的用户名,主机名和登录时间,最后请求开始时间和最后请求结束时间 SELECT session_id AS spid, login_time, host_name, program_name, nt_user_name, last_request_start_time, last_request_end_time FROM sys.dm_exec_sessions WHERE session_id IN(52,54); -- 4,可通過動態管理視圖sys.dm_exec_requests查詢到導致阻塞的進程的詳細信息 SELECT session_id AS spid, blocking_session_id, command, sql_handle, database_id, wait_type, wait_time, wait_resource FROM sys.dm_exec_requests WHERE blocking_session_id>0; -- 利用KILL<spid>命令終止導致阻塞的進程 -- 該操作會導致Connection 1中的事務回滾 KILL 51;
时间: 2024-11-11 07:53:34