`
messon619
  • 浏览: 45336 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

数据库中锁机制的学习

阅读更多
我们在做很多项目时都要涉及到数据库,特别是一些比较大型的web项目,更是有较大的并发处理,所以对数据库的操作有可能会产生死锁,对于数据库的死锁,一般数据库系统都会有一套机制去解锁,一般不会造成数据库的瘫痪,但解锁的过程会造成数据库性能的急速下降,反映到程序上就会造成程序的反应性能的下降,并且会造成程序有的操作失败。虽然一般对于数据库级别的锁定于解锁程序员不会在程序中用代码编程去处理,但是对于其的了解对于程序员来说还是很有好处的,它能让我们在出现问题时快速找到问题的原因,同时让我们在编程时注意哪些可能造成数据库死锁的不太好的编码。
       以下以sql server2000为例,来了解数据库死锁的一些知识(其实各种大型数据库所采用的锁的基本理论是一致的,但在具体实现上各有差别。)
        之所以要有锁的概念是因为存在着多用户同时需要访问数据库,如果没有锁定且多个用户同时访问一个数据库,则当他们的事务同时使用相同的数据时可能会发生问题,这些问题包括:丢失更新、脏读、不可重复读和幻觉读等等,在这就不一一解释了,总之就是发生数据不一致现象。
       在sql server2000中锁是具有粒度的,即可以对不同的资源加锁。锁定在较小的粒度的资源(例如行)上可以增加系统的并发量但需要较大的系统开销,从而也会影响系统的性能,因为锁定的粒度较小则操作可能产生的锁的数量会增加;锁定在较大的粒度(例如表)就并发而言是相当昂贵的,因为锁定整个表限制了其它事务对表中任意部分进行访问,但要求的开销较低,因为需要维护的锁较少,所以在这里是一种互相制约的关系。
        Sql server2000中锁定的粒度包括 行、页、扩展盘区、表、库等资源。实际上这些粒度大多可以看成是sql server系统的空间管理的不同,在SQL Server 2000系统中,最小的空间管理单位是页,一个页有8K。所有的数据、日志、索引都存放在页上。另外,使用页有一个限制,这就是表中的一行数据必须在同一个页上,不能跨页。页上面的空间管理单位是盘区,一个盘区是8个连续的页。表和索引的最小占用单位是盘区。数据库是由一个或者多个表或者索引组成,即是由多个盘区组成。放在一个表上的锁限制对整个表的并发访问;放在盘区上的锁限制了对整个盘区的访问;放在数据页上的锁限制了对整个数据页的访问;放在行上的锁只限制对该行的并发访问。
        在sql server2000中锁的加载和释放一般是有数据库系统自动完成,并且在sql server中,还支持锁升级(lock escalation)。所谓锁升级是指调整锁的粒度,将多个低粒度的锁替换成少数的更高粒度的锁,以此来降低系统负荷。
        在SQL Server数据库中加锁时,除了可以对不同的资源加锁,即锁具有不同粒度,还可以使用不同程度的加锁方式,即锁有多种模式,SQL Server中锁模式包括:
1.       共享锁 SQL Server中,共享锁用于所有的只读数据操作。共享锁是非独占的,允许多个并发事务读取其锁定的资源。
2.         更新锁 更新锁在修改操作的初始化阶段用来锁定可能要被修改的资源,这样可以避免使用共享锁造成的死锁现象。因为使用共享锁时,修改数据的操作分为两步,首先获得一个共享锁,读取数据,然后将共享锁升级为排它锁,然后再执行修改操作。这样如果同时有两个或多个事务同时对一个事务申请了共享锁,在修改数据的时候,这些事务都要将共享锁升级为排它锁。这时,这些事务都不会释放共享锁而是一直等待对方释放,这样就造成了死锁。如果一个数据在修改前直接申请更新锁,在数据修改的时候再升级为排它锁,就可以避免死锁。
3.排它锁 排它锁是为修改数据而保留的。它所锁定的资源,其他事务不能读取也不能修改
4.结构锁 执行表的数据定义语言 (DDL) 操作(例如添加列或除去表)时使用架构修改 (Sch-M) 锁。
5.意向锁 意向锁说明SQL Server有在资源的低层获得共享锁或排它锁的意向。
6.大容量更新锁 当将数据大容量复制到表,且指定了 TABLOCK 提示或者使用 sp_tableoption 设置了 table lock on bulk 表选项时,将使用大容量更新 锁。大容量更新锁允许进程将数据并发地大容量复制到同一表,同时防止其它不进行大容量复制数据的进程访问该表。
       在sql server除了由系统自动的加锁外,也可以靠写sql语句来手动的加锁(显示加锁)。我们可以使用 SELECT、INSERT、UPDATE 和 DELETE 语句指定表级锁定提示的范围,以引导 Microsoft SQL Server 2000 使用所需的锁类型。当需要对对象所获得锁类型进行更精细控制时,使用表级锁定提示更改默认的锁定行为。所指定的表级锁定提示有如下几种:
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的作用是允许用户先读取数据(而且不阻塞其他用户读数据),并且保证在后来再更新数据时,这一段时间内这些数据没有被其他用户修改。
       上面我们主要讲了数据库中锁的分类和显示加锁的一些知识,下面讲一讲关于数据库死锁的问题。
        在数据库系统中,死锁是指多个用户(进程)分别锁定了一个资源,并又试图请求锁定对方已经锁定的资源,这就产生了一个锁定请求环,导致多个用户(进程)都处于等待对方释放所锁定资源的状态。还有一种比较典型的死锁情况是当在一个数据库中时,有若干个长时间运行的事务执行并行的操作,当查询分析器处理一种非常复杂的查询例如连接查询时,那么由于不能控制处理的顺序,有可能发生死锁现象。
例如分别同时执行下面的两个事务
A:
DECLARE @au_id varchar(11), @au_lname varchar(40)
SELECT @au_id = '111-11-1111', @au_lname = 'test1'
BEGIN TRANSACTION
INSERT Authors VALUES
(@au_id, @au_lname, '', '', '', '', '', '11111', 0)
WAITFOR DELAY '00:00:05'
SELECT *
FROM authors
WHERE au_lname LIKE 'Test%'
COMMIT
B:
DECLARE @au_id varchar(11), @au_lname varchar(40)
SELECT @au_id = '111-11-1112', @au_lname = 'test2'
BEGIN TRANSACTION
INSERT Authors VALUES
(@au_id, @au_lname, '', '', '', '', '', '11111', 0)
WAITFOR DELAY '00:00:05'
SELECT *
FROM authors
WHERE au_lname LIKE 'Test%'
COMMIT
则数据库就会出现死锁。原因在于在 5 秒钟内同时执行A和B。每个事务都要等待至少 5 秒钟的时间才能发出 SELECT 语句,所有每个连接都将完成 INSERT 操作,这样就保证了两个事务中的 INSERT 操作在各自的SELECT 语句发布前就已经完成了。每个事务中的 SELECT 语句都尝试读取 authors 表格中的所有数据,查找 au_lname 字段值中类似“Test%”格式的数据。因此,两个事务中的 SELECT 语句都将尝试读取各自连接中的插入数据 — 也读取对方连接中的插入数据。而READ COMMITTED 隔离级别通过发布共享锁确保 SELECT 语句永远不读取未提交的数据。对于同一个资源,共享锁与排它锁互不兼容,请求者在发布共享锁之前必须等待排它锁释放。每个连接对于插入的数据都设置了排它锁,因此尝试读取对方插入数据的 SELECT 语句将试图解除插入数据的共享锁,但它会被阻塞。两个连接将互相阻塞,从而形成一个死锁。
       在SQL Server中,系统能够自动定期搜索和处理死锁问题。系统在每次搜索中标识所有等待锁定请求的进程会话,如果在下一次搜索中该被标识的进程仍处于等待状态,SQL Server就开始递归死锁搜索。当搜索检测到锁定请求环时,SQL Server 通过自动选择可以打破死锁的线程(死锁牺牲品)来结束死锁。SQL Server 回滚作为死锁牺牲品的事务,通知线程的应用程序(通过返回 1205 号错误信息),取消线程的当前请求,然后允许不间断线程的事务继续进行。SQL Server 通常选择运行撤消时花费最少的事务的线程作为死锁牺牲品。另外,用户可以使用 SET 语句将会话的 DEADLOCK_PRIORITY 设置为 LOW。DEADLOCK_PRIORITY 选项控制在死锁情况下如何衡量会话的重要性。如果会话的设置为 LOW ,则当会话陷入死锁情况时将成为首选牺牲品。
        我们除了靠数据库本身来处理死锁外,我们在sql server2005中也可通过try/catch来处理产生的问题。以下为msdn上关于这个问题的描述:
        让我们来使用 TRY/CATCH 语句修改代码正文。(对于本示例,需要以 SQL Server 2005 版本运行代码。)使用 TRY/CATCH 时,操作代码和错误处理代码是分开的。您应该将执行一个操作的代码放在 TRY 语句块中,将错误处理代码放在 CATCH 语句块中。如果 TRY 语句块中的代码执行失败,代码执行将跳到 CATCH 语句块。(除了那些防碍整个批处理运行的错误(如,丢失对象),该方法几乎适用于所有的错误。)
       以下示例使用 TRY/CATCH 语句对前面使用的代码进行了改写。代码标题相同,但是代码正文不同:
BEGIN TRANSACTION
BEGIN TRY
INSERT Authors VALUES
(@au_id, @au_lname, '', '', '', '', '', '11111', 0)
WAITFOR DELAY '00:00:05'
SELECT COUNT(*) FROM Authors
COMMIT
END TRY
BEGIN CATCH
SELECT ERROR_NUMBER() AS ErrorNumber
ROLLBACK
END CATCH;
SELECT @@TRANCOUNT AS '@@Trancount'
       现在,在连接到 SQL Server 2005 的并列窗口中运行这些代码,在此之前您需要确认已经删除了 authors 表格中任何可能阻止插入操作的数据;或者,您可以使用前置 DELETE 语句。
       两个窗口返回的 @@TRANCOUNT 级别都为 0,这表明仍然发生了死锁,但 TRY/CATCH 语句捕获了这次发生的死锁。死锁牺牲品的批处理没有再次中止,可在它的输出结果中看到错误:
ErrorNumber
-----------
1205

@@Trancount
-----------
0
       您应该已经发现 TRY/CATCH 语句具有的威力了。因为死锁错误能够为 CATCH 语句块所捕获,所以批处理将不再中止,T-SQL 代码也能继续执行。对于死锁牺牲品而言,死锁错误 1205 将代码放入 CATCH 语句块 — 在这里您可以使用新的错误处理函数浏览死锁错误。前置代码仅使用 ERROR_NUMBER() 函数取代 @@ERROR 变量,您也可以使用 ERROR_MESSAGE()、ERROR_PROCEDURE()、ERROR_SEVERITY() 和 ERROR_STATE()。这些函数的功能一目了然,它们提供的功能比我们以往使用的更多。
       请注意,这个前置 CATCH 语句块包含一个 ROLLBACK。这样做的原因是,即使捕获了死锁错误,事务也不会回滚。事务仍然要失败,但是,现在您有责任在 TRY/CATCH 语句中回滚事务。那么,区别在哪里?尽管您不能使事务继续进行,但是您能够重试事务!
       在 SQL Server 2000 的 T-SQL 中,错误 1205 令人沮丧之处是它提供的建议:“Rerun the transaction.”问题是,至少在 SQL Server 2000 的 T-SQL 中,您不能做到这一点。但是,由于 SQL Server 2005 的 TRY/CATCH 为我们提供了捕获死锁错误的方法,现在,重试事务是可能实现的。
       以下代码正文说明了一种执行重试操作的方法。这段代码仍然使用与前面相同的标题:
DECLARE @Tries tinyint
SET @Tries = 1
WHILE @Tries <= 3
BEGIN
BEGIN TRANSACTION
BEGIN TRY
    INSERT Authors VALUES
      (@au_id, @au_lname, '', '', '', '', '',
'11111', 0)
    WAITFOR DELAY '00:00:05'
    SELECT * FROM authors WHERE au_lname LIKE 'Test%'
    COMMIT
    BREAK
END TRY
BEGIN CATCH
    SELECT ERROR_NUMBER() AS ErrorNumber
    ROLLBACK
    SET @Tries = @Tries + 1
    CONTINUE
END CATCH;
END
       这段代码的功能是通过一个 WHILE 循环添加一个重试操作。我将重试次数设置为 3,重试次数是可以配置的。至少我们现在有了一种在 T-SQL 内重试一个死锁牺牲品代码的方法 — 这是我们过去一直无法做到的。
       但是,需要注意整个事务是在 WHILE 循环内进行的 — 而不是在循环外部。因此执行循环时,事务不仅在每个循环体内部开始,而且也在其中结束 — 不是 TRY 语句块执行完毕,返回一个 COMMIT,就是 CATCH 语句块执行,返回一个 ROLLBACK。如果 TRY 成功,TRY 语句块将以一个 BREAK 语句结束,退出 WHILE 循环。否则,CATCH 语句块将重试计数器加 1,以一个 CONTINUE 语句结束本次循环,重新执行下次 WHILE 循环。事实上,您有实现重试事务的代码 — 就像错误 1205 告诉我们做的那样。但现在,重试操作完全在 T-SQL 内部完成。
       SQL Server 2005 也提供帮助解决死锁问题的其他方法,例如 SNAPSHOT ISOLATION 级别和用于 READ COMMITTED 的新选项(称为 READ COMMITTED SNAPSHOT)。然而,这一事实 — 现在,通过 SQL Server 2005,您能够对事务进行编码并捕获死锁错误(并重试它们) — 已经意味着您拥有一个可任意支配、功能更加强大的工具。
       在后一篇转贴的文章中我们将对sql server2000中产生死锁的问题作一个总结,来帮助我们如何在实际使用中尽量减少死锁!
  • doc.rar (26.8 KB)
  • 下载次数: 1
分享到:
评论

相关推荐

    MSSQLServer数据库事务锁机制分析.docx

    ### MSSQLServer数据库事务锁机制分析 #### 一、引言 锁机制是数据库系统中一个...通过这些资料的学习,开发者们可以更全面地掌握SQL Server锁机制的细节,并将其应用于实际项目中,以提高数据库应用的性能和可靠性。

    DB数据库锁机制及问题PPT学习教案.pptx

    数据库锁机制是数据库管理系统中用于控制并发操作的重要概念,它确保了多个用户或事务在访问数据库时的数据一致性。本教程将深入探讨DB数据库的锁机制及其常见问题。 首先,锁可以应用于不同层次的对象,包括数据库...

    数据库锁学习文档

    在Oracle数据库中,锁进一步细分为DML锁(数据锁)和DDL锁(字典锁)。DML锁用于确保数据完整性,而DDL锁则用于保护数据库对象的结构。此外,还有内部锁,主要用于数据库内部结构的保护,例如Latch,这是一种轻量级...

    基础数据库学习

    了解锁的类型和锁机制的实现原理是数据库并发控制的基础。 11. 日志系统:理解MySQL的慢查询日志、二进制日志、InnoDB引擎日志和MySQL的其他日志有助于数据库故障恢复和性能监控。 12. 备份与恢复:数据库备份是...

    数据库 数据库学习资料

    事务处理是数据库中的关键概念,确保数据的一致性和完整性。ACID(原子性、一致性、隔离性、持久性)是事务的四个基本属性,确保了数据操作的正确性。同时,数据库安全性涉及到权限管理、角色分配和审计日志,防止...

    DB数据库锁机制及问题PPT课件.pptx

    - 在DB2数据库中,不同类型的锁之间可能存在兼容性问题。例如,一个持有S锁的事务不允许其他事务在同一数据项上加X锁,但可以加S锁。 - 表级锁和行级锁之间的兼容性也有所不同,具体取决于DB2的具体实现细节。 **...

    数据库讲义 很好的数据库讲义,适合学习数据库

    同时,当多个用户同时访问数据库时,并发控制机制(如锁、多版本并发控制MVCC)保证数据的一致性。 6. **备份与恢复**:数据库的容灾策略和恢复技术是保证数据安全的重要环节。讲义可能包括全备、增量备份、差异...

    查看数据库锁和解锁方法

    ### 查看数据库锁和解锁方法 ...通过具体的示例代码,我们不仅学习了如何查询锁定信息,还了解了如何安全地解锁数据库中的会话。希望这些知识能够帮助你在日常的数据库管理和开发工作中更加得心应手。

    数据库入门学习资料包

    学习锁机制、乐观锁与悲观锁、多版本并发控制(MVCC)等概念,有助于理解并发控制的原理。 10. **安全性与权限管理**:数据库的安全性涉及到用户认证、授权和审计等方面。了解如何设置用户权限,防止未授权访问,...

    《数据库系统概论》学习的相关截图

    在本压缩包中,包含了一系列与该主题相关的截图,主要涉及函数依赖公理、范式理论、无损连接性以及事务处理中的锁机制。 首先,函数依赖公理是关系数据库理论的基础,它描述了属性间的关系,特别是一个属性(或一组...

    数据库并发控制PPT学习教案.pptx

    封锁粒度是指对数据库中的某些资源加锁的粒度,可以是行级锁、页级锁、表级锁等。 在数据库并发控制中,还有一些其他概念,如活锁和死锁。活锁是指两个或多个事务循环等待对方释放资源,导致事务无法继续执行。死锁...

    ORACLE数据库教程-SQL学习篇.ppt

    在本教程中,我们将学习如何使用锁机制来控制并发访问,并了解不同的锁机制对数据库性能的影响。 SQL优化是ORACLE数据库中的最后一个重要概念,涉及到如何优化SQL语句以提高数据库性能。在本教程中,我们将学习如何...

    数据库多粒度封锁学习攻略

    如果没有意向锁机制,系统就需要检查表中的每一行是否已经有X锁或S锁,这将极大地增加锁冲突检查的开销。通过使用意向锁,系统只需要检查表本身的锁状态,而不需要检查每一行的锁状态,大大提高了处理速度。 #### ...

    数据库-基础知识点学习(软考)

    数据库基础知识点学习是数据库管理系统(DBMS)的核心组成部分,涉及到数据库设计、关系数据库规范化、事务管理、数据库安全、数据库管理系统、数据独立性、事务并发控制、分布式数据库等多方面的知识点。...

    SQL语句大全(数据库学习)

    2. 锁:MySQL支持多种锁机制,如行级锁、表级锁、读写锁等,用于解决并发问题。 四、性能优化 1. 查询优化:分析`EXPLAIN`输出,理解查询计划,合理使用索引,避免全表扫描。 2. 索引维护:定期分析和优化索引,...

    数据库系统概论学习指导与习题解答(PDF)

    3. **关系模型**:关系模型是数据库中最常见的模型,由关系、元组、属性和键等概念构成。关系代数和SQL(结构化查询语言)是操作关系数据库的主要工具。 4. **SQL语言**:SQL是用于管理关系数据库的标准语言,包括...

    数据库系统概论学习指导与习题解答

    2. **并发控制**:锁机制、时间戳等方法解决事务并发执行过程中可能出现的问题。 3. **故障恢复**:日志记录、检查点技术等手段确保系统在发生故障时能够恢复到一致状态。 #### 六、高级主题 1. **索引技术**:B树...

    数据库系统概论 (第四版) 学习指导与习题解析

    6. 数据库事务处理与并发控制:解释事务的概念,包括事务的ACID属性(原子性、一致性、隔离性和持久性),以及并发控制的策略和方法,如锁机制、时间戳等。 7. 数据库系统的性能优化:提供数据库性能调优的策略和...

Global site tag (gtag.js) - Google Analytics