一、锁
1、定义
在数据库中,除了传统的计算资源(如CPU、RAM、I/O等)的争用以外, 数据也是一种供需要用户共享的资源。如何包管数据并发访问的一致性、有效性 是所有数据库必须办理的一个问题,锁冲突也是影响数据库并发访问性能的一个 重要因素。
2、分类
- 性能区分: 乐观锁、灰心锁;
- 数据库使用: 读锁、写锁 (都是灰心锁);
- 共享锁(读锁): 同一条数据,多个select可以同时举行而不会相互影响 ;
- 排它锁(写锁):一个使用没有commit或rollback前,他会阻断其他的读锁和写锁;
- 数据使用: 表锁、行锁;
二、表锁
1、定义
每次使用锁住整张表。开销小,加锁快;不会出现死锁;锁定粒度大,发生锁冲 突的概率最高,并发度最低;
2、演示
2.1、创建表、新增数据
- ‐‐建表SQLCREATE TABLE `user` ( `id` int NOT NULL AUTO_INCREMENT COMMENT '主键', `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci DEFAULT NULL COMMENT '用户名', `salary` int DEFAULT NULL COMMENT '工资金额', PRIMARY KEY (`id`)) ENGINE=MyISAM DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户账户';-- 插入数据INSERT INTO `user` VALUES ('1', 'super', '4900');INSERT INTO `user` VALUES ('2', 'admin', '6000');INSERT INTO `user` VALUES ('3', 'manage', '7000');
复制代码 图示:
2.2 表加锁、检察锁、释放锁
- 加锁:
- lock table 表名 read;
备注:
- 当前session和其他的session 都可以select这张表的数据;
- 当前session在执行INSERT、UPDATE就会报错。其他session执行INSERT、UPDATE就会等候,如果等候超时时间内锁释放了,sql执行成功如果没有就会超时失败;
- lock table 表名 write;
备注:
- 当前session执行SELECT、INSERT、UPDATE、DELETE都是没有问题的,其他session执行就会阻塞等候;
- 检察
- 释放
2.3、小总结
MyISAM在执行SELECT前,会自动给涉及的所有表加读锁,在执行增删改 使用前,会自动给涉及的表加写锁。
- 对MyISAM表的读使用(加读锁) ,不会阻寒其他进程对同一表的读请求,但是会阻赛对同一表的写请求。只有当读锁释放后,才会执行别的进程的写使用。
- 对MylSAM表的写使用(加写锁) ,会阻塞其他进程对同一表的读和写使用,只有 当写锁释放后,才会执行别的进程的读写使用
重要: 读锁会阻塞写,但是不会阻塞读。而写锁则会把读和写都阻塞
三、行锁
1、定义
每一个使用锁住一行数据开销大,加锁慢;就会出现死锁;锁定粒度最小,发生锁冲突的概率最低,并发度最高。 这就是为什么高并发项目表的存储引擎一般选用INNODB;
2、事务的特性
事务是由一组SQL语句组成的逻辑处理处罚单元,事务具有下面四个特性,通常简称为事务的ACID属性。
- 原子性( Atomicity ):SQL语句要么全部执行,要么全都不执行。没有一半一半的事。
- 一致性( Consistent ):在事务开始和完成时,数据都必须保持一致状态,意味着所有相关数据规则都必须应用于事务的修改,以保持数据的完整性。事务结束时所有的内部数据结构也都必须是正确的。
- 隔离性( Isolation ):同一时间,只允许一个事务请求同一数据,差别的事务之间相互没有任何关扰。
- 持久性 ( Durable ):事务完成后,对数据的变动应该是永久性的,纵然系统出现故障,也要保持事务完成后的变动数据。
3、事务的隔离级别
3.1 、并发使用的问题
- 脏读( Dirty Reads ):当前事务(A)中可以读到其他事务(B)未提交的数据(脏数据),这种现象是脏读
- 不可重复读( Non-Repeatable Reads ):在事务A中先后两次读取同一个数据,两次读取的效果不一样,这种现象称为不可重复读。
- 幻读( Phantom Reads ):在事务A中按照某个条件先后两次查询数据库,两次查询效果的条数差别,这种现象称为幻读。
3.2、隔离级别
隔离级别脏读不可重复度幻读读未提交大概大概大概读已提交不大概大概大概可重复读不大概不大概大概串行化不大概不大概不大概备注:隔离级别越严格,并发越小。
3.3、图文演示
- ##设置隔离级别:mysql> set session transaction isolation level read uncommitted;## 查询隔离级别:mysql> select @@transaction_isolation;
复制代码 4、可重复读( repeatable-read )
4.1、设置隔离级别
4.2、查询、更新
4.2.1、执行顺序
- 左边窗口开启事务;
- 执行 select * from user;
- 右边窗口开启事务,执行步调2;
- 右边窗口执行update使用,执行步调2;
- 右边窗口提交事务commit;
- 左边窗口步调2,两次查询的效果是一样的,没有出现不可重复读的问题;
7. 左边窗口接着执行update user set salary = salary - 100 where id = 1, salary没有酿成5000-100=4900;
8. super的salary值用的是步调7中的4900来算的,所以是4800,数据的一致性倒是没有被粉碎。可重复读的 隔离级别下使用了MVCC(multi-version concurrency control)机制,select使用 不会更新版本号,是快照读(汗青版本);insert、update和delete会更新版本 号,是当前读(当前版本)。
5、读已提交( read-committed)
5.1、设置隔离级别
5.2、查询、更新
- 两个窗口分别开始session;
- 都想执行select * from user;
- 右窗口先执行UPDATE更新语句后,执行步调2的使用;
- 左窗口执行步调2的使用。这时候右边窗口的没有执行commit使用,所以左边窗口无法查询到右边窗口已经更新的数据,到这我们就办理了脏读的问题
5.2.1 、提交事务后
5. 上图右边窗口提交update事务后,左边窗口在执行与上一步相同的查询,效果 与上一步不一致,即产生了不 可重复读的问题 ;
6、读未提交(read-uncommitted)
6.1、设置隔离级别
6.2、查询、更新
- 左边窗口开启事务,执行select查询;
- 右边窗口开启事务,执行select查询;
- 右边窗口执行update使用,执行select查询;
- 右边窗口,左边窗口执行select查询,左边窗口可以查询到右边窗口未提交事务的update使用;
- 右边窗口执行rollback使用,此时左边窗口再次执行查询使用就会出现脏数据
- 左边窗口在执行 update user set salary = salary - 100 where id = 1; 按照显示是4600-100=4500。但是效果真是这样吗? 你要是这样明确就真的太天真 了,在应用步调中,我们会用4700-100=4600,并不知道其他会话回滚了,要想办理这个问题可以采用读已提交的隔离级别;
7、串行化
7.1、设置隔离级别;
下面篇我们先容一下mysql的mvcc,间隙锁
来源:https://blog.csdn.net/qq_36481052/article/details/111994464
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |