SQL实战新手入门:理解锁

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了SQL实战新手入门:理解锁相关的知识,希望对你有一定的参考价值。

参考技术A

   理解锁

  在一个多用户环境中 并发是最重要的问题之一 当多个会话向共享的资源读取或写入数据时 数据可能丢失它的完整性 为了避免出现这种情况 每一个称职的RDBMS都实现了并发控制机制 对于RDBMS服务器 通过各种锁机制来管理并发 所有RDBMS(包括MicrosoftAccess)都实现了一些复杂的并发管理机制 尽管SQL标准为游标声明了锁定 但锁定既不是SQL的一部分 也不是一种标准(游标是一种用于逐行访问数据的特殊结构)

  Oracle的锁机制可能是最先进也是最复杂的 它遵循这样的规则 读取和写入进程相互之间不能阻碍对方 即使它们正在访问相同(或接近)的数据集 在Oracle中 每一个会话将接收到一个读一致的数据快照 因此 即使某些其他进程已经开始修改数据集中的数据 但只要并未提交这些修改 随后的每一会话将依然能从快照中读取到原来的数据 一旦在第一个会话中提交了更改 则其他每一个会话也都能看到更改后的数据 仅当将修改提交到数据库时才需要锁 Oracle自动选择限制最小的锁 用户可以选择手动锁定一个资源(例如一个表) 在这种情况下 根据使用的锁类型 其他用户可能依然能够访问这些数据

  IBM DB 和Microsoft SQL Server 都使用了锁 这两种数据库中的锁允许读取操作锁定写入操作 或者写入操作锁定读取操作 并发访问数据的问题在某种程度上由于锁的粒度(就是对表 页 列或行的锁)得以缓解 对于只读的查询 DDL语句 DML查询等 都需要获得相应的锁 在绝大多数情况下 用户无须担心锁的问题 RDBMS将自动地为特定的操作选择最合适的锁(或者多个锁) 只有在程序逻辑失败的情况下 才需要使用SQL语句以手动方式声明锁

  mysql本身仅在表级别上锁定数据 它依赖于支持事务的InnoDB(或者IBMDB I)存储引擎和附加的行级别锁定和事务支持 PostgreSQL具有健壮的表级和行级锁定机制 每一种锁定机制都有良好的粒度

   锁定模式

  并发的模式可以分为两大类 乐观并发和悲观并发 这两个术语是不言自明的 乐观并发模式的事务假定当多个事务工作于同一个数据集时 不太可能发生资源冲突的情况(尽管有可能发生冲突 但将任何潜在的问题留给数据库去解决) 乐观事务检查当把修改提交给数据库时潜在的冲突 并通过重新提交数据来解决冲突的问题(在这种情况下 最后提交的数据具有优先权) 悲观并发模式的事务设想从一开始就存在冲突 并锁定它们试图使用的资源 尽管悲观并发模式能确保数据最高级别的一致性 但它也是最昂贵的 可能会使数据库陷入停顿 通常情况下 RDBMS既支持乐观并发模式 也支持悲观并发模式 有时用户可以指定事务使用其中一种并发模式 悲观并发模式提供了更好的一致性 但必须付出性能的代价

  锁的粒度对数据库系统的性能有显著的影响 行级别的锁可以增加并发性(它不会阻塞其他事务对表的访问) 但也常常引起过多的管理开销 降低数据库的性能 就系统资源方面而言 全表锁定具有较小的开销 但代价就是降低了系统的并发性和性能 在设计数据库应用程序时应该注意这两个问题

  锁用于实现悲观并发模式的事务 每一种RDBMS都具有自己的锁级别 但它们都是大同小异的 通常根据使用资源的方式 将其分为共享锁和排他锁

  例如 下面的语句以排他模式锁定了LIBRARY数据库的BOOKS表

  LOCK TABLE books IN EXCLUSIVE MODE;

  发出该语句的事务将试图锁定表 以排他方式使用 但是允许执行SELECT语句 如果任何其他进程在该表上保持了一个锁 则该事务将被放到一个队列中 当接收到优先权时它将获得锁 在该事务期间 该锁将被一直持有(直到执行了MIT语句) 在不同的RDBMS中 该语句实际的语法可能不尽相同 但差别不大

  锁机制也带来了一个潜在的问题 如果一个已经在表上持有锁的事务试图获得另外一个资源上的锁 但是第二个事务已经对该资源进行了锁定 就可能发生死锁的情况(请参考下一小节)

  某些数据库 特别是Microsoft SQL Server 和IBM DB 已经实现了一种称为锁提升的机制 该术语指的是将很多个精细的锁转换为 更粗放 的 高级别的锁 以减少系统在锁管理上的开销 Oracle g/ g希望在系统资源上具有更好的并发性 因此它从不对锁进行提升 另外 MySQL(使用InnoDB存储引擎)和PostgreSQL都不支持锁提升机制

  所有的锁都是由RDBMS酌情决定的(并非用户配置的) 默认的锁是行级锁 可以将一个行级锁提升为一个表级锁 可以使用前面介绍的LOCKTABLE语句提升锁级别 锁提升的阈值则由DBA配置

  高粒度的锁(即行级别的锁)是有代价的 因为SQL Server需要为行级别的锁定操作分配更多的资源 因此它会降低SQL Server的性能 另外也增加了死锁发生的可能性

  关于各个RDBMS中所支持的不同锁类型之间的比较 请参考本书的网站 wrox 或者访问 agilitator

   处理死锁

  发生死锁的典型情形是 两个(或多个)会话都在等待获得某个共享资源上的锁 但是这两个会话都不能继续执行 因为第一个会话在第二个会话要求的资源上有一个锁 而第二个会话在第一个会话所要求的某个其他资源上也具有一个锁 可以设想这样的情形 会话 持有资源A并试图访问资源B 而会话 持有资源B并且试图访问资源A 在这种情况下就会发生死锁

  通常情况下 RDBMS采用这样的办法来解决死锁问题 自动地杀掉其中一个进程并回滚该进程已经执行的所有操作

  Oracle实现了一种复杂的机制 用于执行如下规则 读取和写入进程不能相互阻塞对方 该规则背后的思想是 为每一个进程提供一个一致的数据映像 其中不包含未提交的更改 尽管如此 在Oracle中依然会发生死锁问题 并由RDBMS来进行判决 在极少的情况下 需要手动解决死锁问题 选择 牺牲 一个死锁的进程 最常见的死锁类型是ORA (排队死锁)和ORA (库缓存死锁) 可以声明NOWAIT子句或者设置会话超时来避免死锁 另外还可以使用其他一些技术来避免死锁 例如显式锁定和事务的隔离级别 通过Oracle的界面也可以手动解决死锁问题

  IBM DB 运行一个后台进程Deadlock Detector 用于发现和解决死锁问题 被选定作为死锁牺牲品的会话将被回滚 并产生一个特殊的错误(SQLCODE SQLSTATE ) DB 主要选择只读进程作为死锁的牺牲品 然后再应用 最小开销 条件来选择要杀掉的会话 如果总是出现死锁的问题 IBM建议使用系统监视工具来收集关于死锁情况的信息 要么优化系统 要么重新设计引起死锁的应用程序

  Microsoft SQL Server 采用了一种私有的死锁检测算法 并采用与其他RDBMS实现的类似方法来解决死锁问题 Microsoft SQL Server 可以自动地处理死锁问题 用户也可以通过Enterprise Manager Console手动处理死锁问题 通过在会话中设置DEADLOCK_PRIORITY参数 Microsoft SQL Server 可以找到一个自愿作为死锁牺牲品的会话(请参考本章之前关于会话的讨论)

  PostgreSQL和MySQL试图通过中止其中一个竞争的事务来解决死锁的问题

  总而言之 避免死锁的最佳实践包括首先就运行较小的事务 尽可能快地运行提交命令 重构访问表的逻辑 减少显式锁定指令的使用等

       返回目录 SQL实战新手入门

       编辑推荐

       Oracle索引技术

       高性能MySQL

lishixinzhi/Article/program/SQL/201311/16446

第25天SQL进阶-查询优化- performance_schema系列实战二:锁问题排查(全局读锁)(SQL 小虚竹)

回城传送–》《32天SQL筑基》

文章目录

零、前言

今天是学习 SQL 打卡的第 25 天,每天我会提供一篇文章供群成员阅读( 不需要订阅付钱 )。

希望大家先自己思考,如果实在没有想法,再看下面的解题思路,自己再实现一遍。在小虚竹JAVA社区 中对应的 【打卡贴】打卡ÿ

以上是关于SQL实战新手入门:理解锁的主要内容,如果未能解决你的问题,请参考以下文章

SQL-mysql架构入门

SQL实战新手入门:前言

《SQL Server 2008从入门到精通》--20180716

SQL实战新手入门:删除视图

SQL实战新手入门:EXCEPT和MINUS操作符

SQL注入实战新手教程