• 数据库锁总结 【转】


    一:锁的概念

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

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

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

    二:锁的分类

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

            锁的分类,在教材上,网络上好多都是按两个维度来描述的。一种维度是按锁的功能来划分,一种维度是按概念来划分。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 --此时是查不出结果的,会无限地等待下去,因为排它锁未释放,默认查询的共享锁与之不兼容,所以就一直等待排它锁的释放,才会返回结果,即使表中已有许多数据,而排它锁只锁了一条记录,但是,查询语句也要等待这一条记录的锁的释放,才会返回结果。 这便是人工手动设置的因为排它锁未释放而导致的死锁(不是相互等待,而是一方无尽的等待!)。

    欢迎讨论。

    无欲则刚 关心则乱
  • 相关阅读:
    支付宝小程序InputItem清除icon不显示
    win11 激活 wi7 win11 魔兽争霸切换 后无法 回到游戏界面 处理办法
    HJ10 字符个数统计
    iOS 15系统导航栏适配
    HJ4 字符串分隔
    HJ7 取近似值
    [iOS]隐藏导航栏3种方式
    HJ3 明明的随机数
    HJ8 合并表记录
    HJ5 进制转换
  • 原文地址:https://www.cnblogs.com/xjyxp/p/11164952.html
Copyright © 2020-2023  润新知