请你谈谈数据库的锁机制?

1对MySQL的锁了解吗

解决数据库并发事务的时,可能会产生数据的不一致的问题,通过锁机制来保证访问的次序。

**基于锁的属性分类:共享锁、排他锁。**共享锁(share lock) :共享锁又称读锁,简称S锁;当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,直到所有的读锁释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现重复读的问题。

排他锁(exclusive lock) :排他锁又称写锁,简称X锁;当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁。排他锁的目的是在数据修改时候,不允许其他人同时修改,也不允许其他人读取,避免了出现脏读的问题。

基于锁的粒度分类:行级锁(innodb )、表级锁 ( innodb. myisam)、页级锁 ( innodb引擎)、 记录锁、间隙锁、临键锁。

表锁(table lock) :表锁是指上锁的时候锁住的是整个表,当下一个事务访问该表的时候,必须等前一个事务释放了锁才能进行对表进行访问,特点:粒度大,加锁简单,容易冲突;

行锁:行锁是指上锁的时候锁住的是表的某一行或多行记录,其他事务访问同一张表时,只有被锁住的记录不能访问,其他的记录可正常访问,特点:粒度小,加锁比表锁麻烦,不容易冲突,相比表锁支持的并发要高;

记录锁(Record lock) :记录锁也属于行锁中的一种,只不过记录锁的范围只是表中的某一条记录,记录锁是说事务在加锁后锁住的只是表的某一条记录, 加了记录锁之后数据可以避免数据在查询的时候被修改的重复读问题,也避免了在修改的事务未提交前被其他事务读取的脏读问题;

页锁:页级锁是MysQL中锁定粒度介于行级锁和表级锁中间的一种锁。表级锁速度快,但冲突多。行级冲突少,但速度慢。所以取了折衷的页级,一次锁定相邻的一组记录。特点:开销和加锁时间界于表锁和行锁之间,会出现死锁;锁定粒度界于表锁和行锁之间,并发度一般;

间隙锁:是属于行锁的一种,间隙锁是在事务加锁后其锁住的是表记录的某一个区间, 当表的相邻ID之间出现空隙则会形成一个区间,遵循左开右闭原则。范围查询并且查询未命中记录,查询条件必须命中索引、间隙锁只会出现在REPEATABLE_ READ (重复读)的事务级别中。

临键锁(Next-Key lock):也属于行锁的一种,并且它是INNODB的行锁默认算法,总结来说它就是记录锁和间隙锁的组合,临键锁会把查询出来的记录锁住,同时也会把该范围查询内的所有间隙空间也会锁住,再之它会把相邻的下一个区间也会锁住。

2隔离级别与锁的关系

隔离级别
Read Uncommitted 允许读取尚未提交的数据读取数据不需要加共享锁,这样就不会跟被修改的数据上的排他锁冲突
Read Committed 允许读取并发事务已经提交的数据读操作需要加共享锁,但是在语句执行完以后释放共享锁
Repeatable Read读操作需要加共享锁,但是在事务提交之前并不释放共享锁,也就是必须等待事务执行完毕以后才释放共享锁
SERIALIZABLE一直持有锁,直到事务完成

2什么是死锁?怎么解决?

死锁是指两个或两个以上的进程在执行过程中,由于竞争资源或者由于彼此通信而造成的一种阻塞的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态,这些永远在互相等待的进程称为死锁进程。

常见的解决数据库死锁的方法

1、【破坏循环等待条件】如果不同程序会并发存取多个表,尽量约定以相同的顺序访问表。
2、【破坏请求与保持条件】在同一个事务中,尽可能做到一次锁定所需要的所有资源;
3、对于非常容易产生死锁的业务部分,可以尝试使用升级锁定颗粒度,通过表级锁定来减少死锁产生的概率;
4、如果业务处理不好可以用分布式事务锁或者使用乐观锁。

3数据库的乐观锁和悲观锁是什么?怎么实现的?

数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。乐观并发控制(乐观锁)和悲观并发控制(悲观锁)是并发控制主要采用的技术手段。

锁类别解释实现方式使用场景
悲观锁对数据被的修改持悲观态度(认为数据在被修改的时候一定会存在并发问题),因此在整个数据处理过程中将数据锁定数据库锁机制多写
乐观锁乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。版本号机制、CAS多读

4 间歇锁

https://www.cnblogs.com/phyger/p/14377651.html

间隙锁锁的是索引叶子节点的next指针。解决了mysql RR级别下是幻读的问题。

快照读:在RR隔离级别下:快照读有可能读到数据的历史版本,也有可能读到数据的当前版本。所以快照读无需用锁也不会发生幻读的情况。

当前读:select…lock in share mode,select…for update
当前读:update,delete,insert
读取的是记录的最新版本,所以就需要通过加锁(行锁 间隙锁 表锁)的方式,使得被当前读读过的数据不能被新增修改或者删除,换句话说再来一次当前读要返回相同的数据。

CREATE TABLE `z` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `b` int(11) DEFAULT NULL,
  `c` int(255) NOT NULL DEFAULT '0',
  PRIMARY KEY (`id`),
  KEY `b` (`b`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;


INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('1', '1', '0');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('3', '6', '1');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('5', '4', '2');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('7', '8', '3');
INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('8', '10', '4');

在这里插入图片描述
begin; select * from z where b = 6 for update;
这条sql语句之后看看我们 需要做什么才能保证不发生幻读。

1不能插入b为6的数据

2不能删除b为6的数据

3不能修改b为6的数据

4不能把别的数据修改为b为6

mysql大牛灵机一动,给叶子节点5的next指针加锁,给叶子节点3加行锁,给叶子节点3的next指针加锁。如下图所示:
在这里插入图片描述
两个next指针锁解决了插入b为6或者把别的数据修改为b为6,行锁解决了修改b为6的行,但是呢也带来一些明显的副作用:

INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('6', '4', '0'); 

会bolck因为按照索引结构这条数据会插入到叶子结点5和3之间,会修改叶子节点5的next指针,虽然这条sql没有破坏上述的4个红色条件但是依然被阻塞了所以我叫它为副作用。

INSERT INTO `study`.`z` (`id`, `b`, `c`) VALUES ('4', '4', '0'); 

插入成功因为这条数据会插入在1的后面5的前面。

间歇锁的范围:

begin; 
select * from z where id=4 for update;

1——>3——>5——>7——>8
会锁住主键索引叶子节点的3的next指针。

begin; 
select * from z where id=3 for update;

间隙锁会退化为行锁只锁叶子节点3 ,为什么因为没必要。不加间隙锁也不会打破上述的红色4个条件。

begin; 
select * from z where id>4 for update;

叶子节点3及之后所有节点会加行锁并且他们的next指针会加锁。

begin; 
select * from z where c=2 for update;

会发生锁表,因为c没有索引结构能存储行锁或者间隙锁。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值