mysql中的悲观锁和乐观锁
迪丽瓦拉
2024-01-29 10:43:21
0
悲观锁:获取数据时都会直接加锁,共享资源每次只给一个线程使用,其它线程阻塞等待。在数据库中提供了行锁、表锁等,操作数据时先加锁后使用。例如售票系统 select * from ticket where id=100 for update 乐观锁:不是数据库系统自带的,需要开发实现。乐观锁是只操作数据时并不进行任何特殊处理,也就是不加锁,在进行更新时才进行冲突判
在数据表中添加一个额外列:version数据版本号或者使用时间戳timestamp,每次修改数据则版号加1 update tb_users set age=80,version=2 where id=5 and version=1 第一次读取数据的版本 号为1,修改时条件为version=1的那条数据。如果中间有事务已经修改了数据,则版本号绝 对不是1,所以该语句执行返回结果为0 如果执行结果为0,则重新读取数据,重新执行修改操作
锁模式 记录锁:在行相应的索引记录上的锁,锁定一个行记录. 它会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。 gap锁:间隙锁是封锁索引记录中的间隔,或者第一条索引记录之前的范围,又或者最后一 条索引记录之后的范围 临键锁next-key锁是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间。 MYSQL8 RR级别下默认使用临键锁.临键锁的主要目的,也是为了避免幻读(Phantom Read)。如果 把事务的隔离级别降级为RC,临键锁则也会失效 意向锁:是为了支持多种粒度锁同时存在; 锁分类 全局锁:就对整个数据库实例加锁,加锁后整个实例就处于只读状态,后续的MDL、DDL语句、更 新操作的事务提交语句都将被阻塞。其典型的使用场景是做全库的逻辑备份,对所有的表进行锁 定,从而获取一致性视图,保证数据的完整性         flush tables with read lock;         unlock table 行级锁         S 共享锁 :允许获取到此锁的事务读取行         X 排他锁 :允许获取到此锁的事务update,delete行 表级锁-意向锁         表级锁会对当前操作的整张表加锁,最常使用的 MyISAM 与 InnoDB 都支持表级锁定         lock tables xxx read/write;         IS 意向共享锁:事务打算对表中的行设置共享S锁         IX 意向排他锁:事务打算对表中的行设置排他X锁         意向锁是 InnoDB 自动加的, 不需用户干预 意向锁定协议         事务在获得表中某行上的共享锁之前,必须先获得表上的IS锁或更高级别的锁         在事务可以获得表中某一行上的排他锁之前,它必须首先获得表上的IX锁
验证,比如表aa,需要开启set AUTOCOMMIT = FALSE; X: lock tables aa write; S: lock tables aa read; IX: select * from aa where 1=2 for update; IS: select * from aa where 1=2 lock in share mode;
按加锁方式分类 按加锁方式划分,可分为自动锁、显示锁。 隐式加锁:         InnoDB自动加意向锁         对于UPDATE、DELETE和INSERT语句,InnoDB会自动给涉及数据集加排他锁         对于普通SELECT语句,InnoDB不会加任何锁;         随时都可以执行锁定,InnoDB会根据隔离级别在需要的时候自动加锁;锁只有在执行commit或者rollback的时候才会释放,并且所有的锁都是在同一时刻被释放。 显式加锁:         共享锁S:SELECT * FROM table_name WHERE … LOCK IN SHARE MODE         排他锁X :SELECT * FROM table_name WHERE … FOR UPDATE 按照算法分类 按照算法分类,可分为间隙锁、临键锁、记录锁。 间隙锁:间隙锁基于非唯一索引,它锁定一段范围内的索引记录。使用间隙锁锁住的是一个区间, 而不仅仅是这个区间中的每一条数据。 select * from tb_users where id between 1 and 10 for update; 即所有在( 1,10)区间内的记录行都会被锁住,所有id 为 2、3、4、5、6、7、8、 9 的数据行的插入会被阻塞,但是 1 和 10 两条记录行并不会被锁住 临键锁是记录锁与间隙锁的组合,它的封锁范围,既包含索引记录,又包含索引区间,是一个左开 右闭区间。临键锁的主要目的,也是为了避免幻读Phantom Read。如果把事务的隔离级别降级为 RC,临键锁则也会失效。每个数据行上的非唯一索引列上都会存在一把临键锁,当某个事务持有该 数据行的临键锁时,会锁住一段左开右闭区间的数据。需要强调的一点是,InnoDB 中行级锁是基 于索引实现的,临键锁只与非唯一索引列有关,在唯一索引列(包括主键列)上不存在临键锁。 记录锁是封锁记录,记录锁也叫行锁,如 select *from tb_users where id=1 for update; 它 会在 id=1 的记录上加上记录锁,以阻止其他事务插入,更新,删除 id=1 这一行。 相关锁总结 记录锁、间隙锁、临键锁,都属于排它锁 记录锁就是锁住一行记录 间隙锁只有在事务隔离级别 RR可重复读 中才会产生         唯一索引只有锁住多条记录或者一条不存在的记录的时候,才会产生间隙锁,指定给某条存在的记录加锁的时候,只会加记录锁,不会产生间隙锁         普通索引不管是锁住单条,还是多条记录,都会产生间隙锁         间隙锁会封锁该条记录相邻两个键之间的空白区域,防止其它事务在这个区域内插入、修改、删除数据,这是为了防止出现幻读现象 普通索引的间隙,优先以普通索引排序,然后再根据主键索引排序 事务级别是RC读已提交级别的话,间隙锁将会失效 表级锁:开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲突的概率最高,并发度最低。 行级锁:开销大,加锁慢;会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度也最高。 页面锁:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间,并发度

相关内容