Ⅰ、锁的概念
1.1 锁的作用
- 对共享资源进行并发访问
- 提供数据的完整性和一致性
1.2 锁的实现
每个数据库的锁的实现完全不同
- MyISAM表锁
- InnoDB行级锁
Like Oracle???不一样 - Microsoft SQL Server 行级锁with锁升级
行锁超过5000个就升级为行级锁或者表锁
MySQL做的很棒,但是很难理解。
1.3 latch(闩锁)
- mutex 互斥锁
- rw-lock
他们是锁吗?
latch在内存中,控制内存数据结构的并发访问,针对程序内部资源(比如:全局变量),锁的是并发资源(临界区),lock是数据库层的锁,针对的是事务,锁的对象不是内存结构而是行
数据库中发生死锁会选择一个事务回滚,程序层中没有死锁检测
latch无处不在,对某一个对象并发访问的控制,和lock也没啥好比较的,完全不搭界
lock由latch来保证和实现
tips:
如何查看latch? 了解即可,基本用不着
(root@localhost) [(none)]> show engine innodb mutex;
+--------+---------------------------+----------+
| Type | Name | Status |
+--------+---------------------------+----------+
| InnoDB | rwlock: dict0dict.cc:1184 | waits=3 |
| InnoDB | rwlock: log0log.cc:838 | waits=23 |
+--------+---------------------------+----------+
2 rows in set (0.00 sec)
即使很大也没什么意义,代表不了什么,waits很长就代表这个latch有并发
某时间点数据写入量很大,那重做日志的这把latch可能就会很大
读取量大的话,bp的latch可能会很大
Ⅱ、 演示锁
session1:
(root@localhost) [test]> show create table lG
*************************** 1. row ***************************
Table: l
Create Table: CREATE TABLE `l` (
`a` int(11) NOT NULL,
`b` int(11) DEFAULT NULL,
`c` int(11) DEFAULT NULL,
`d` int(11) DEFAULT NULL,
PRIMARY KEY (`a`),
UNIQUE KEY `c` (`c`),
KEY `b` (`b`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4
1 row in set (0.00 sec)
(root@localhost) [test]> select * from l;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 2 | 4 | 6 | 8 |
| 4 | 6 | 8 | 10 |
| 6 | 8 | 10 | 12 |
| 8 | 10 | 12 | 14 |
+---+------+------+------+
4 rows in set (0.00 sec)
(root@localhost) [test]> begin;
Query OK, 0 rows affected (0.00 sec)
(root@localhost) [test]> delete from l where a = 2;
Query OK, 1 row affected (0.00 sec)
(root@localhost) [test]> update l set b = b + 1 where a = 4;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
(root@localhost) [test]> select * from l;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 4 | 7 | 8 | 10 |
| 6 | 8 | 10 | 12 |
| 8 | 10 | 12 | 14 |
+---+------+------+------+
3 rows in set (0.00 sec)
此时这两条记录上就被加了排他锁,在当前session看到这两条记录已经变化了
再开一个session看到的还是原来的记录,因为事务还没提交,mvcc特性
session2:
(root@localhost) [test]> select * from l;
+---+------+------+------+
| a | b | c | d |
+---+------+------+------+
| 2 | 4 | 6 | 8 |
| 4 | 6 | 8 | 10 |
| 6 | 8 | 10 | 12 |
| 8 | 10 | 12 | 14 |
+---+------+------+------+
4 rows in set (0.00 sec)
(root@localhost) [test]> show engine innodb statusG
...
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 29474225, ACTIVE 46 sec
2 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2
MySQL thread id 296696, OS thread handle 140076853794560, query id 34555618 localhost root
Trx read view will not see trx with id >= 29474796, sees < 29474796
...
通常认为增删改会加排它锁,其实select也可以加,select后面用一个for update就对这条记录加锁了,但是这个锁住了没事,新开session依然可以读,mvcc机制————默认读永远不会被锁,即使你在全表更新
但新开session去select也加for update这时候就会等待了