MySQL锁

## 锁是网络数据库中的一个非常重要的概念,当多个用户同时对数据库并发操作时,会带来数据不一致的问题,所以,锁主要用于多用户环境下保证数据库完整性和一致性。

`帮助理解:以商场的试衣间为例,每个试衣间都可供多个消费者使用,因此,可能出现多个消费者同时需要使用试衣间试衣服。为了避免冲突,试衣间装了锁,某一个试衣服的人在试衣间里把锁锁住了,其他顾客就不能从外面打开了,只能等待里面的顾客试完衣服,从里面把锁打开,外面的人才能进去。`

<!--more-->

### 数据库锁出现的目的,或者说是想要解决什么问题?

 答案就是:高并发  
 在当今互联网发达的今天,每一个生活中我们使用的软件都会出现高并发问题,如果没有数据库锁,那么很有可能就会出现一些非常恐怖的问题。
 
 比如:当我们在淘宝购买一件衣服的时候,我们同时五个人购买,如果货源只剩一件的情况,那么由谁来获得这件衣服的购买权呢?如果没有锁,有可能就会出现这种情况,显示还剩一件衣服,但是大家都一起下单,一起付款,就会出现脏数据,五个人都购买成功,这样是非常麻烦的事情。

## 并发控制的主要采用的技术手段:乐观锁、悲观锁和时间戳。 

## 锁的分类:

从数据库系统角度分为三种:排他锁、共享锁、更新锁。 
从程序员的角度分析: 乐观锁,悲观锁


## 悲观锁(Pessimistic Lock)

顾名思义,很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人拿这个数据就会block(阻塞),直到它拿锁。
悲观锁(Pessimistic Lock):正如其名,具有强烈的独占和排他特性。它指的是对数据被外界(包括本系统当前的其他事务,以及来自外部系统的事务处理)修改持保守态度,因此,在整个数据处理过程中,将数据处于锁定状态。悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也无法保证外部系统不会修改数据)。


*传统的关系数据库里用到了很多这种锁机制,比如行锁、表锁、读锁、写锁等,都是在操作之前先上锁。*

## 共享锁(Share Lock)

S锁,也叫读锁,用于所有的只读数据操作。共享锁是非独占的,允许多个并发事务读取其锁定的资源。 
性质 
1. 多个事务可封锁同一个共享页; 
2. 任何事务都不能修改该页; 
3. 通常是该页被读取完毕,S锁立即被释放。

`例如:在SQL Server中,默认情况下,数据被读取后,立即释放共享锁。 
例如,执行查询语句“SELECT * FROM my_table”时,首先锁定第一页,读取之后,释放对第一页的锁定,然后锁定第二页。这样,就允许在读操作过程中,修改未被锁定的第一页。 
例如,语句“SELECT * FROM my_table HOLDLOCK”就要求在整个查询过程中,保持对表的锁定,直到查询完成才释放锁定。`

## 排他锁(Exclusive Lock)

X锁,也叫写锁,表示对数据进行写操作。如果一个事务对对象加了排他锁,其他事务就不能再给它加任何锁了。(某个顾客把试衣间从里面反锁了,其他顾客想要使用这个试衣间,就只有等待锁从里面打开了。) 
性质 
1. 仅允许一个事务封锁此页; 
2. 其他任何事务必须等到X锁被释放才能对该页进行访问; 
3. X锁一直到事务结束才能被释放。
  `产生排他锁的sql语句 select * from ljd_user for update`

## 更新锁(update lock)

U锁,在修改操作的初始化阶段用来锁定可能要被修改的资源,这样可以避免使用共享锁造成的死锁现象。

```
因为当使用共享锁时,修改数据的操作分为两步: 
1. 首先获得一个共享锁,读取数据, 
2. 然后将共享锁升级为排他锁,再执行修改操作。 
这样如果有两个或多个事务同时对一个事务申请了共享锁,在修改数据时,这些事务都要将共享锁升级为排他锁。这时,这些事务都不会释放共享锁,而是一直等待对方释放,这样就造成了死锁。 
如果一个数据在修改前直接申请更新锁,在数据修改时再升级为排他锁,就可以避免死锁。
```

## 行锁

行锁的作用范围为行级别

## 表锁
表锁的作用范围为整张表
数据库能够确定那些行需要锁的情况下使用行锁,如果不知道会影响哪些行的时候就会使用表锁。

比如,当我们执行一个sql 明确指定唯一id,where id = ?时,这里只会修改某一行的数据,数据库就会上行锁,如果没有指定具体的id,那么数据库就会给给这张表上表锁。


## 乐观锁(Optimistic Lock)

顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以,不会上锁。但是在更新的时候会判断一下在此期间别人有没有更新这个数据,可以使用版本号等机制。

```
乐观锁( Optimistic Locking ): 相对悲观锁而言,乐观锁机制采取了更加宽松的加锁机制。 
悲观锁大多数情况下依靠数据库的锁机制实现,以保证操作最大程度的独占性。但随之而来的就是数据库性能的大量开销,特别是对长事务而言,这样的开销往往无法承受。而乐观锁机制在一定程度上解决了这个问题。 
乐观锁,大多是基于数据版本( Version )记录机制实现。 
数据版本:为数据增加一个版本标识,在基于数据库表的版本解决方案中,一般是通过为数据库表增加一个 “version” 字段来实现。读取出数据时,将此版本号一同读出,之后更新时,对此版本号加一。此时,将提交数据的版本数据与数据库表对应记录的当前版本信息进行比对,如果提交的数据版本号大于数据库表当前版本号,则予以更新,否则认为是过期数据。
```

## 活锁
定义:指的是T1封锁了数据R,T2同时也请求封锁数据R,T3也请求封锁数据R,当T1释放了锁之后,T3会锁住R,T4也请求封锁R,则T2就会一直等待下去。 
解决方法:采用“先来先服务”策略可以避免。

## 死锁
定义:就是我等你,你又等我,双方就会一直等待下去。比如:T1封锁了数据R1,正请求对R2封锁,而T2封住了R2,正请求封锁R1,这样就会导致死锁,死锁这种没有完全解决的方法,只能尽量预防。 
预防方法: 
1. 一次封锁法,指的是一次性把所需要的数据全部封锁住,但是这样会扩大了封锁的范围,降低系统的并发度; 
2. 顺序封锁法,指的是事先对数据对象指定一个封锁顺序,要对数据进行封锁,只能按照规定的顺序来封锁,但是这个一般不大可能的。 系统判定死锁的方法:

超时法:如果某个事物的等待时间超过指定时限,则判定为出现死锁;
等待图法:如果事务等待图中出现了回路,则判断出现了死锁。
对于解决死锁的方法,只能是撤销一个处理死锁代价最小的事务,释放此事务持有的所有锁,同时对撤销的事务所执行的数据修改操作必须加以恢复。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值