数据库-锁的实践

一:锁的概念

按照写技术博客的套路,应该对锁的概念做一个介绍,我又想,能点击进入本篇博客的同学,想必都是听说过锁的。所以我尽量用简练的语言来表述一下。

锁的定义:锁主要用于多用户环境下,保证数据库完整性和一致性的技术。

锁的解释:当多个用户并发地存取数据时,在数据库中就会产生多个事务同时存取同一数据的情况。若对并发操作不加控制就可能会读取和存储不正确的数据,破坏数据库的完整性和一致性。当事务在对某个数据对象进行操作前,先向系统发出请求,对其加锁。加锁后事务就对该数据对象有了一定的控制。

二:锁的分类

锁的概念非常简单,简单的来用几句话就能描述它的用途。但是锁的分类,就明显要复杂一些了。

锁的分类,在教材上,网络上好多都是按两个维度来描述的。一种维度是按锁的功能来划分,一种维度是按概念来划分。09年的时候,我做了一个数据库的培训教程,把锁的分类给截出来摆一下。

时隔了几年,看起来PPT看起来很粗糙。与我这些PPT模板没法比,但是内容仍然经典。

三:锁的关键字

共享锁,排它锁这样的锁,数据库引擎会自动管理和优化,平时写SQL的时候,很少有去关心锁的关键字。

但是今天是抱着学习的态度来看博客的,所以必须得把这几个关键字都用一篇。

SELECT * FROM AppLog WITH (HOLDLOCK) /*共享锁*/

SELECT * FROM AppLog WITH (UPDLOCK)  /*更新锁*/ 

SELECT * FROM AppLog WITH (XLOCK) WHERE LogID=‘AA599A4E-B727-4A65-8010-00001661765E‘; /*排它锁*/  

SELECT * FROM AppLog WITH (ROWLOCK) WHERE LogID=‘6BE2C680-0C9F-43FA-9B4E-00000A6C1CEF‘; /*行锁*/ 

SELECT * FROM AppLog WITH (TABLOCKX) /*大容量更新锁*/ 

SELECT * FROM AppLog WITH (XLOCK,ROWLOCK) WHERE LogID=‘AA599A4E-B727-4A65-8010-00001661765E‘; /*锁的组合使用*/ 

/*XLOCK 本身是锁住数据行的,TABLOCKX是锁住整张表*/

SELECT * FROM AppLog WITH (NOLOCK)   /*不加锁,当一个事务回滚后,出现脏数据*/   

SELECT * FROM AppLog WITH (READPAST)  /*忽略掉加锁的数据(行数据,页数据)*/

四:死锁的发生

比如现在的数据库用两个用户在用,

用户1:

BEGIN TRAN
SELECT * FROM AppLog WHERE LogID  = ‘A10BA165-6E52-4AFB-9EA8-000000D6B90A‘;
UPDATE AppLog SET AppPostion = AppPostion + AppPostion WHERE LogID = ‘A10BA165-6E52-4AFB-9EA8-000000D6B90A‘;

用户2:

BEGIN TRAN
SELECT * FROM AppLog WHERE LogID  = ‘A10BA165-6E52-4AFB-9EA8-000000D6B90A‘;
UPDATE AppLog SET AppPostion = AppPostion + AppPostion WHERE LogID = ‘A10BA165-6E52-4AFB-9EA8-000000D6B90A‘;

比如用户1,用户2同时执行 SELECT,用户1对记录加了共享锁,用户2对记录也加了共享锁,当用户1 SELECT 执行完毕,准备执行UPDATE的时候,根据锁机制,用户1的共享锁需要升
级到排他锁才能执行接下来的UPDATE.

在升级排他锁前,必须等待记录上的其它共享锁释放,但是因为共享锁只有等事务结束后才释放。因为用户2的共享锁不释放而导致用户1等(等用户2释放共享锁,自己好升级成排他锁),同理,这时也因为用户1的共享锁不释放而导致用户2等待。死锁就发生了。

五:无锁查询技巧

打开两个查询窗口:其中一个执行下面语句:

CREATE TABLE a
(
    id INT ,
    name NVARCHAR(20)
)
BEGIN TRAN
INSERT a VALUES (‘1‘,‘a‘)--开启一个事务,而不提交也不回滚,此时insert 语句产生的排它锁是不会释放的

在另一个窗口中执行:

select COUNT(*) from a with(nolock)--无锁查询,会查出结果为1

select COUNT(*) from a with(readpast)--忽略所有有锁的记录,此时为0

然后执行select * from a --此时是查不出结果的,会无限地等待下去,因为排它锁未释放,默认查询的共享锁与之不兼容,所以就一直等待排它锁的释放,才会返回结果,即使表中已有许多数据,而排它锁只锁了一条记录,但是,查询语句也要等待这一条记录的锁的释放,才会返回结果。 这便是人工手动设置的因为排它锁未释放而导致的死锁(不是相互等待,而是一方无尽的等待!)。

欢迎讨论。

时间: 2024-10-04 01:45:18

数据库-锁的实践的相关文章

如何合理使用数据库锁

一.前言 死锁,在我们的项目中有发生过,但不频繁:但是因为锁处理的不好,不能合理地规划锁,导致性能下降是经常发生的.通过本文章,除了了解如何避免死锁外,更多的内容是如何使用锁.本文不会讲的很细,有的地方也不是很严谨,但是不影响对内容的理解.更细节和高级的知识,可以百度. 二.什么是锁 我们这里讲的锁,是数据库的锁(lock).当数据库要对某个表,或者某条数据修改时,会首先将其加锁,防止其他进程或事务修改它,以免产生不可预期的结果.关于锁的定义,锁的类型,大家可以搜索.锁的内容(或者称为对象,比如

数据库锁总结

http://www.cnblogs.com/ismallboy/p/5574006.html 数据库锁出现的原因是为了处理并发问题,因为数据库是一个多用户共享的资源,当出现并发的时候,就会导致出现各种各样奇怪的问题,就像程序代码一样,出现多线程并发的时候,如果不做特殊控制的话,就会出现意外的事情,比如"脏"数据.修改丢失等问题.所以数据库并发需要使用事务来控制,事务并发问题需要数据库锁来控制,所以数据库锁是跟并发控制和事务联系在一起的. 平时会经常看到或者听到数据库锁有"共

【转】数据库锁机制

1 前言 数据库大并发操作要考虑死锁和锁的性能问题.看到网上大多语焉不详(尤其更新锁),所以这里做个简明解释,为下面描述方便,这里用T1代表一个数据库执行请求,T2代表另一个请求,也可以理解为T1为一个线程,T2 为另一个线程.T3,T4以此类推.下面以SQL Server(2005)为例. 2 锁的种类 共享锁(Shared lock). 例1: ---------------------------------------- T1: select * from table (请想象它需要执行

数据库锁的基本原理

数据库锁的基本原理 为了保证数据的完事性和一致性,数据库系统采用锁来实现事务的隔离性.各种大型数据库采用的锁基本理论是一致的,但在具体实现上各有差别. 从并发事务锁定的关系上看,可以分为共享锁定和独占锁定.从锁定的对象不同,一般可以分为表锁定和行锁定. 锁 共享锁用于读取数据操作,它是非独占的,允许其他事务同时读取其锁定的资源,但不允许其他事务更新它. 独占锁也叫排他锁,适用于修改数据的场合.它所锁定的资源,其他事务不能读取也不能修改. 当一个事务访问某种数据库资源时,如果执行select语句,

ABAP锁、数据库锁

声明:原创作品,转载时请注明文章来自SAP师太技术博客:www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将追究法律责任!原文链接:http://www.cnblogs.com/jiangzhengjun/p/4293533.html ABAP数据锁定... 338 SM12锁查看与维护... 344 通用加锁与解锁函数... 344 ABAP程序锁定... 345 数据库锁... 347 锁的分类和兼容性... 347 并发性与锁的权衡... 34

数据库锁机制

1 前言 数据库大并发操作要考虑死锁和锁的性能问题.看到网上大多语焉不详(尤其更新锁),所以这里做个简明解释,为下面描述方便,这里用T1代表一个数据库执行请求,T2代表另一个请求,也可以理解为T1为一个线程,T2 为另一个线程.T3,T4以此类推.下面以SQL Server(2005)为例. 2 锁的种类 共享锁(Shared lock). 例1: ---------------------------------------- T1: select * from table (请想象它需要执行

数据库锁之乐观锁

一.乐观锁的介绍 乐观锁是相对悲观锁而言,也是为了避免数据库幻读.业务处理时间过长等原因引起数据处理错误的一种机制,但乐观锁不会刻意使用数据库本身的锁机制,而是依据数据本身来保证数据的正确性. 乐观锁的机制:对每条数据库加上版本号或时间撮,在每次对数据进行操作(尤其是修改操作)时,总会带上版本号获取数据同时更改后修改版本号. 二.乐观锁的代码示例 2.1 创建一张表 create table em_oplock ( id VARCHAR(100) not null, value VARCHAR(

20个设计数据库的最佳实践指南

数据库设计看上去很简单,但是如果不经意随意设计,可能会为日后维护拓展或性能方面埋下祸根.以下是20个设计数据库的最佳实践指南: 1. 使用完整的一致的数据表名称和字段名,如:School, StudentCourse, CourseID 2.数据表名称使用单数,比如使用StudentCourse 而不是StudentCourses,数据表代表实体的一个集合,因此没有必要使用复数名称. 3. 数据表名称不要使用空格,比如StudentCourse 比Student Course更好. 4.数据表名

基于Oracle数据库锁机制,解决集群中的并发访问问题

1.需求 应用场景是这样的: 使用Oracle数据保存待办任务,使用状态字段区分任务是否已经被执行.多个Worker线程同时执行任务,执行成功或失败后,修改状态字段的值. 假设数据库表结构如下所示. create table Task( id varchar2(32), name varchar2(32), flag varchar2(1), worker varchar2(32) ); flag 可取的值包括:0-待办,1-已办,-1-失败待重试. 需要避免的问题: 多个Worker同时工作时