如何解除表的锁定
如何解除表的锁定
如何解除表的锁定锁是数据库中的一个非常重要的概念,它主要用于多用户环境下保证数据库完整性和一致性。 我们知道,多个用户能够同时操纵同一个数据库中的数据,会发生数据不一致现象。即如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题。这些问题包括:丢失更新、脏读、不可重复读和幻觉读。但是在操作数据库的时候,有时候会由于操作不当引起数据库表被锁定。
一、数据库中的锁有以下几种
1. Shared locks (S) 共享锁
USE AdventureWorks2008
BEGIN TRAN
select * from Sales.SalesOrderHeader WITH(HOLDLOCK)
where SalesOrderID='43662'
SELECT resource_type, request_mode, resource_description,request_session_id, DB_NAME(resource_database_id)as resource_database
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'
--ROLLBACK TRAN
2. Update locks (U): 更新锁
是共享锁和独占锁的组合.用UPDLOCK保持更新锁
放置在可更新的资源(如行、页、表)上的锁。更新锁用于防止常见形式的死锁,这类死锁在多个会话锁定资源并且稍后可能更新资源时发生。
USE AdventureWorks2008
BEGIN TRAN
select * from Sales.SalesOrderHeader WITH(UPDLOCK)
where SalesOrderID='43662'
SELECT resource_type, request_mode, resource_description,request_session_id,DB_NAME(resource_database_id)as resource_database
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'
ROLLBACK TRAN
3.Exclusive locks (X): 独占锁
是为了锁定数据被一个session修改的数据, 而不能够被另外的session修改. 只能指定NOLOCK来读取.
USE AdventureWorks2008
BEGIN TRAN
update Sales.SalesOrderHeader set ShipDate=GETDATE() where SalesOrderID='43662'
SELECT resource_type, request_mode, resource_description,request_session_id,DB_NAME(resource_database_id)as resource_database--,*
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE'
ROLLBACK TRAN
4.Intent locks (I): 意向锁
用于建立锁的层次结构. 意向锁包含三种类型:意向共享 (IS)、意向排他 (IX) 和意向排他共享 (SIX)。
数据库引擎使用意向锁来保护共享锁(S 锁)或排他锁(X 锁)放置在锁层次结构的底层资源上。 意向锁之所以命名为意向锁,是因为在较低级别锁前可获取它们,因此会通知意向将锁放置在较低级别上。
意向锁有两种用途:
- 防止其他事务以会使较低级别的锁无效的方式修改较高级别资源。
- 提高数据库引擎在较高的粒度级别检测锁冲突的效率。
5. Schema locks (Sch): 架构锁
- Schema stability lock(Sch-S): 保持架构稳定性,用在生成执行计划时,不会阻止对数据的访问.
- Schema modification lock (Sch-M):用在DDL操作时.当架构正在被改变时, 阻止对对象数据的访问.
USE AdventureWorks2008
BEGIN TRAN
CREATE TABLE MyTable (ID INT, NAME VARCHAR(20),COUNTRY VARCHAR(15))
SELECT resource_type, request_mode, resource_description
FROM sys.dm_tran_locks
WHERE resource_type <> 'DATABASE' order by request_mode
ROLLBACK TRAN
6. Bulk Update locks (BU)
数据库引擎在将数据大容量复制到表中时使用了大容量更新 (BU) 锁, 并指定了 TABLOCK 提示或使用 sp_tableoption 设置了 table lock on bulk load 表选项. 大容量更新锁(BU 锁)允许多个线程将数据并发地大容量加载到同一表, 同时防止其他不进行大容量加载数据的进程访问该表.
7. Key - Range locks
在使用可序列化事务隔离级别时, 对于 Transact-SQL 语句读取的记录集, 键范围锁可以隐式保护该记录集中包含的行范围. 键范围锁可防止幻读. 通过保护行之间键的范围, 它还防止对事务访问的记录集进行幻像插入或删除.
二、SQL Server锁类型
(1) HOLDLOCK: 在该表上保持共享锁,直到整个事务结束,而不是在语句执行完立即释放所添加的锁。
(2) NOLOCK:不添加共享锁和排它锁,当这个选项生效后,可能读到未提交读的数据或“脏数据”,这个选项仅仅应用于SELECT语句。
(3) PAGLOCK:指定添加页锁(否则通常可能添加表锁)。
(4) READCOMMITTED用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下,SQL Server 2000 在此隔离级别上操作。
(5) READPAST: 跳过已经加锁的数据行,这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行,而不是阻塞直到其他事务释放锁,READPAST仅仅应用于READ COMMITTED隔离性级别下事务操作中的SELECT语句操作。
(6) READUNCOMMITTED:等同于NOLOCK。
(7) REPEATABLEREAD:设置事务为可重复读隔离性级别。
(8) ROWLOCK:使用行级锁,而不使用粒度更粗的页级锁和表级锁。
(9) SERIALIZABLE:用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。
(10) TABLOCK:指定使用表级锁,而不是使用行级或页面级的锁,SQL Server在该语句执行完后释放这个锁,而如果同时指定了HOLDLOCK,该锁一直保持到这个事务结束。
(11) TABLOCKX:指定在表上使用排它锁,这个锁可以阻止其他事务读或更新这个表的数据,直到这个语句或整个事务结束。
(12) UPDLOCK :指定在 读表中数据时设置更新 锁(update lock)而不是设置共享锁,该锁一直保持到这个语句或整个事务结束,使用UPDLOCK的作用是允许用户先读取数据(而且不阻塞其他用户读数据),并且保证在后来再更新数据时,这一段时间内这些数据没有被其他用户修改。
三、常见的死锁情况及解决方法
1、死锁的第一种情况
一个用户A 访问表A(锁住了表A),然后又访问表B;另一个用户B 访问表B(锁住了表B),然后企图访问表A;这时用户A由于用户B已经锁住表B,它必须等待用户B释放表B才能继续,同样用户B要等用户A释放表A才能继续,这就死锁就产生了。
解决方法
这种死锁比较常见,是由于程序的BUG产生的,除了调整的程序的逻辑没有其它的办法。仔细分析程序的逻辑,对于数据库的多表操作时,尽量按照相同的顺序进行处理,尽量避免同时锁定两个资源,如操作A和B两张表时,总是按先A后B的顺序处理, 必须同时锁定两个资源时,要保证在任何时刻都应该按照相同的顺序来锁定资源。
2、死锁的第二种情况
用户A查询一条纪录,然后修改该条纪录;这时用户B修改该条纪录,这时用户A的事务里锁的性质由查询的共享锁企图上升到独占锁,而用户B里的独占锁由于A有共享锁存在所以必须等A释放掉共享锁,而A由于B的独占锁而无法上升的独占锁也就不可能释放共享锁,于是出现了死锁。这种死锁比较隐蔽,但在稍大点的项目中经常发生。如在某项目中,页面上的按钮点击后,没有使按钮立刻失效,使得用户会多次快速点击同一按钮,这样同一段代码对数据库同一条记录进行多次操作,很容易就出现这种死锁的情况。
解决方法
1、对于按钮等控件,点击后使其立刻失效,不让用户重复点击,避免对同时对同一条记录操作。
2、使用乐观锁进行控制。乐观锁大多是基于数据版本(Version)记录机制实现。即为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个“version”字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。乐观锁机制避免了长事务中的数据库加锁开销(用户A和用户B操作过程中,都没有对数据库数据加锁),大大提升了大并发量下的系统整体性能表现。Hibernate 在其数据访问引擎中内置了乐观锁实现。需要注意的是,由于乐观锁机制是在我们的系统中实现,来自外部系统的用户更新操作不受我们系统的控制,因此可能会造成脏数据被更新到数据库中。
3、使用悲观锁进行控制。悲观锁大多数情况下依靠数据库的锁机制实现,如Oracle的Select … for update语句,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。如一个金融系统,当某个操作员读取用户的数据,并在读出的用户数据的基础上进行修改时(如更改用户账户余额),如果采用悲观锁机制,也就意味着整个操作过程中(从操作员读出数据、开始修改直至提交修改结果的全过程,甚至还包括操作员中途去煮咖啡的时间),数据库记录始终处于加锁状态,可以想见,如果面对成百上千个并发,这样的情况将导致灾难性的后果。所以,采用悲观锁进行控制时一定要考虑清楚。
3、死锁的第三种情况
如果在事务中执行了一条不满足条件的update语句,则执行全表扫描,把行级锁上升为表级锁,多个这样的事务执行后,就很容易产生死锁和阻塞。类似的情况还有当表中的数据量非常庞大而索引建的过少或不合适的时候,使得经常发生全表扫描,最终应用系统会越来越慢,最终发生阻塞或死锁。
解决方法
SQL语句中不要使用太复杂的关联多表的查询;使用“执行计划”对SQL语句进行分析,对于有全表扫描的SQL语句,建立相应的索引进行优化。
- mysql主从同步复制原理(MYSQL数据库GTID实现主从复制实现超级方便)
- dedecms数据库备份(dedecms网站搬家需要的备份的文件)
- sql server怎么导出数据库(sqlserver复制数据库的方法步骤图文)
- mysql数据库调优技术大全(Mysql数据库性能优化三分表、增量备份、还原)
- mysql数据库间的连接(MySQL中表的几种连接方式)
- navicat连接数据库报密码错误(navicat 连接数据库隔段时间后自动断开连接的解决方案)
- python pandas读取数据库表(Python3.5 Pandas模块之DataFrame用法实例分析)
- netcore连什么数据库好(.Net Core导入千万级数据至Mysql的步骤)
- mysql数据库简单优化(MySQL数据类型优化原则)
- 织梦源码安装数据库怎么填(Mysql修改端口号 织梦DedeCMS设置教程)
- 关系数据库中的范式
- SQL Server数据库备份的几种方式
- mysql创建数据库基本指令(MySql 新建用户与数据库的实际操作步骤)
- 查询SQL SERVER中某个数据库的每个表的数据量和每行记录所占用空间
- laravel测试重连数据库(解决在laravel中leftjoin带条件查询没有返回右表为NULL的问题)
- ASP.NET将Excel数据导入到数据库
- 营养餐是什么(学校营养餐是什么)
- 谁说女子不如男 范冰冰演的武则天只是其一,另外两位你认识吗(谁说女子不如男)
- 杯酒人生---瓦伦丁酒杯和奥丁格啤酒(杯酒人生---瓦伦丁酒杯和奥丁格啤酒)
- 中秋节买啤酒,预算超过7元试试这8种啤酒,麦香浓郁都是真啤酒(预算超过7元试试这8种啤酒)
- CellPress旗下的6 期刊,国人友刊来了解一下吧(CellPress旗下的6期刊国人友刊来了解一下吧)
- ()
热门推荐
- sqlserver分页数据重复(SQL Server 在分页获取数据的同时获取到总记录数)
- 免费海外云主机有什么优势(国外云主机有什么优势?怎么选择?)
- pythonsql注入检测(Python版Mssql爆破小脚本)
- canvas图片裁剪插件(浅析图片上传及canvas压缩的流程)
- mysql 慢查询日志
- nginx django部署(uwsgi+nginx代理Django无法访问静态资源的解决)
- docker容器连接宿主机(docker 实现容器与宿主机无缝调用shell命令)
- php怎么创建一个文件(PHP文件后缀不强制为.php方法)
- thinkphp 多维度展示数据(Thinkphp自定义生成缩略图尺寸的方法)
- python中字符串截取规则(Python中的字符串切片截取字符串的详解)
排行榜
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9