zoukankan      html  css  js  c++  java
  • 数据库-锁的实践

    一:锁的概念

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

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

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

    二:锁的分类

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

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

    欢迎讨论。

  • 相关阅读:
    ICONS-图标库
    图形资源
    vue项目中,如果修改了组件名称,vscode编辑器会在引入修改组件的名字处提示红色波浪线 The file is in the program because:Imported via xxx Root file specified for compilation .
    接口在dev环境报跨域问题(has been blocked by CORS policy:Response to preflight request doesn't pass access control check:No 'Access-Control-Allow-Origin' header ispresent on the requested resource.),qa环境正常
    阿里云occ的图片文件URL用浏览器直接打开无法访问,提示This XML file does noe appear to have any style information associated with it. The document tree is shown below.
    vue 项目使用element ui 中tree组件 check-strictly 用法(父子不互相关联的反显情况)
    高德地图进行线路规划绘制标记点操作(vue)
    vue中实现拖拽调整顺序功能
    2021-01-22 浏览器相关知识
    2021-01-22 js 相关知识点
  • 原文地址:https://www.cnblogs.com/xcj26/p/5646078.html
Copyright © 2011-2022 走看看