为什么需要锁?

在任何多用户的数据库中,必须有一套用于数据修改的一致的规则,当两个不同的进程试图同时修改同一份数据时,数据库管理系统(DBMS)负责解决它们之间潜在的冲突。

create table testTable5
(
count int not null
);

insert into testTable5(count)
values(200);

--若以下sql 在5s内被调用两次,就会出现查询结果剩余量不准确
declare @count as int
begin tran
select @count=count from testTable5
WAITFOR DELAY '00:00:05' --模拟并发,故意延迟5秒
update testTable5 set count=@count-1
commit TRAN

SELECT * FROM testTable5

ACID

原子性(Atomicity)

一个事务(transaction)中的所有操作,或者全部完成,或者全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。即,事务不可分割、不可约简。

一致性(Consistency)

在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设约束、触发器、级联回滚等。

隔离性(Isolation)

数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括未提交读(Read uncommitted)、提交读(read committed)、可重复读(repeatable read)和串行化(Serializable)。

未提交读(Read uncommitted):

提交读(read committed) :

可重复读(repeatable read):

串行化(Serializable):

持久性(Durability)

事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

悲观锁:相信并发是绝大部分的,并且每一个线程都必须要达到目的的。

declare @count as int
begin tran
select @count=count from testTable5 WITH(UPDLOCK)
WAITFOR DELAY '00:00:05' --模拟并发,故意延迟5秒
update testTable5 set count=@count-1
commit TRAN

SELECT * FROM testTable5

乐观锁:相信并发是极少数的,假设运气不好遇到了,就放弃并返回信息告诉它再次尝试。因为它是极少数发生的。

表字段增加时间戳,更新前查询当前时间戳 条件加上时间戳,每次更新后,更新时间戳。

若时间第一个人更新后,并发的第二个人由于时间戳不一致,会更新失败。

表级锁,页级锁,行级锁,在mysql和oracle常用,比如oracle 使用pl/sql 工具时;

修改数据时,可以

select * from  表for update  where 条件  ;

锁一张表。

select  t.*,t.rowid  from 表 t  where 条件;

锁行。

共享锁
加锁与解锁:当一个事务执行select语句时,数据库系统会为这个事务分配一把共享锁,来锁定被查询的数据。在默认情况下,数据被读取后,数据库系统立即解除共享锁。例如,当一个事务执行查询“SELECT * FROM accounts”语句时,数据库系统首先锁定第一行,读取之后,解除对第一行的锁定,然后锁定第二行。这样,在一个事务读操作过程中,允许其他事务同时更新accounts表中未锁定的行。

兼容性:如果数据资源上放置了共享锁,还能再放置共享锁和更新锁。

并发性能:具有良好的并发性能,当数据被放置共享锁后,还可以再放置共享锁或更新锁。所以并发性能很好。

排他锁
加锁与解锁:当一个事务执行insert、update或delete语句时,数据库系统会自动对SQL语句操纵的数据资源使用排他锁。如果该数据资源已经有其他锁(任何锁)存在时,就无法对其再放置排他锁了。

兼容性:排他锁不能和其他锁兼容,如果数据资源上已经加了排他锁,就不能再放置其他的锁了。同样,如果数据资源上已经放置了其他锁,那么也就不能再放置排他锁了。

并发性能:最差。只允许一个事务访问锁定的数据,如果其他事务也需要访问该数据,就必须等待。

更新锁
更新锁在的初始化阶段用来锁定可能要被修改的资源,这可以避免使用共享锁造成的死锁现象。例如,对于以下的update语句:

UPDATE accounts SET balance=900 WHERE id=1

更新操作需要分两步:读取accounts表中id为1的记录 –> 执行更新操作。

如果在第一步使用共享锁,再第二步把锁升级为独占锁,就可能出现死锁现象。例如:两个事务都获取了同一数据资源的共享锁,然后都要把锁升级为独占锁,但需要等待另一个事务解除共享锁才能升级为独占锁,这就造成了死锁。

更新锁有如下特征:

加锁与解锁:当一个事务执行update语句时,数据库系统会先为事务分配一把更新锁。当读取数据完毕,执行更新操作时,会把更新锁升级为独占锁。

兼容性:更新锁与共享锁是兼容的,也就是说,一个资源可以同时放置更新锁和共享锁,但是最多放置一把更新锁。这样,当多个事务更新相同的数据时,只有一个事务能获得更新锁,然后再把更新锁升级为独占锁,其他事务必须等到前一个事务结束后,才能获取得更新锁,这就避免了死锁。

并发性能:允许多个事务同时读锁定的资源,但不允许其他事务修改它。

意向锁

待更新。。。。。。。。。。。。。。。。。


原文地址:https://www.cnblogs.com/anyihen/p/12333162.html