INNODB以及MYISAM是MYSQL最常见的两种引擎,5.1的版本以后开启INNODB需要加上--with-plugins=innobase
INNODB以及MYISAM在锁的机制上,差别较为明显:
MYISAM全表锁,而INNODB在表有主键的情况下是行锁,没有主键任然是表锁.
其中 语句SELECT X FROM TABLE FOR UPDATE 这条语句对MYISAM无效,
行级锁的优点如下:
1)、当很多连接分别进行不同的查询时减小LOCK状态。
2)、如果出现异常,可以减少数据的丢失。因为一次可以只回滚一行或者几行少量的数据。
行级锁的缺点如下:
1)、比页级锁和表级锁要占用更多的内存。
2)、进行查询时比页级锁和表级锁需要的I/O要多,所以我们经常把行级锁用在写操作而不是读操作。
3)、容易出现死锁。
3、MySQL用写队列和读队列来实现对数据库的写和读操作。
对于写锁定如下:
1)、如果表没有加锁,那么对其加写锁定。
2)、否则,那么把请求放入写锁队列中。
对于读锁定如下:
1)、如果表没有加写锁,那么加一个读锁。
2)、否则,那么把请求放到读锁队列中。
如果要锁MYISAM的表,可以使用(新增锁会释放之前新增的锁)
#只读 即共享锁 LOCK TABLE READ #读写 即独占锁 LOCK TABLE WRITE
#释放锁 UNLOCK TABLES;
行锁DEMO:
表结构,区别在于引擎,其他完全一致
CREATE TABLE `t` ( `id` int(11) NOT NULL AUTO_INCREMENT, `a` int(11) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=UTF8
数据如下:
mysql> select * from t; +----+------+ | id | a | +----+------+ | 1 | 123 | | 2 | 2 | | 3 | 3 | +----+------+ 3 rows in set (0.00 sec)
开启事务(T1):
mysql> start transaction; Query OK, 0 rows affected (0.00 sec) #锁ID为1的数据 mysql> select * from t where id =1 for update; +----+------+ | id | a | +----+------+ | 1 | 123 | +----+------+ 1 row in set (0.00 sec) #当前操作暂停
mysql> select * from t; +----+------+ | id | a | +----+------+ | 1 | 123 | | 2 | 2 | | 3 | 3 | +----+------+ 3 rows in set (0.01 sec) mysql> mysql> update t set a = 1 where id =1 ; #处于当前状态时,等待T1 释放锁 #释放后的效果: Query OK, 1 row affected (18.08 sec) Rows matched: 1 Changed: 1 Warnings: 0 mysql> select * from t; +----+------+ | id | a | +----+------+ | 1 | 1 | | 2 | 2 | | 3 | 3 | +----+------+ 3 rows in set (0.00 sec)
释放T1:
mysql> rollback; Query OK, 0 rows affected (0.00 sec)
修改非锁定的行:
步骤任然是T1锁定ID=1的数据,而T2尝试修改ID=3的数据:
mysql> select * from t where id = 1 for update; +----+------+ | id | a | +----+------+ | 1 | 1 | +----+------+ 1 row in set (0.00 sec) mysql> select now(); +---------------------+ | now() | +---------------------+ | 2014-01-22 15:43:03 | +---------------------+ 1 row in set (0.00 sec) #锁定ID 为1的数据 mysql> select * from t where id = 1 for update; +----+------+ | id | a | +----+------+ | 1 | 1 | +----+------+ 1 row in set (0.00 sec) #切换到T2 mysql> update t set a=333 where id =2; Query OK, 1 row affected (0.04 sec) Rows matched: 1 Changed: 1 Warnings: 0 #数据没有被锁定 #切换到T1查看数据 #数据已经被修改 mysql> select * from t ; +----+------+ | id | a | +----+------+ | 1 | 1 | | 2 | 333 | | 3 | 3 | +----+------+ 3 rows in set (0.00 sec) #Rollback 再看数据: mysql> rollback; Query OK, 0 rows affected (0.00 sec) mysql> select * from t; +----+------+ | id | a | +----+------+ | 1 | 1 | | 2 | 333 | | 3 | 3 | +----+------+ 3 rows in set (0.00 sec)
读锁和写锁:
#T1 锁定表 mysql> lock table t read; Query OK, 0 rows affected (0.00 sec) #T2尝试读取数据: mysql> select * from t; +----+------+ | id | a | +----+------+ | 1 | 1 | | 2 | 333 | | 3 | 3 | +----+------+ 3 rows in set (0.00 sec) #没有问题, #尝试修改数据: #解锁之前的情况: mysql> select now();update t set a=22 where id =2;select now(); select * from t; +---------------------+ | now() | +---------------------+ | 2014-01-22 15:55:19 | +---------------------+ 1 row in set (0.00 sec) #回到T1解锁: mysql> unlock tables; Query OK, 0 rows affected (0.00 sec) #回到T2看看完整的信息: mysql> select now();update t set a=22 where id =2;select now(); select * from t; +---------------------+ | now() | +---------------------+ | 2014-01-22 15:55:19 | +---------------------+ 1 row in set (0.00 sec) #看这里,整整锁了28S Query OK, 1 row affected (28.01 sec) Rows matched: 1 Changed: 1 Warnings: 0 +---------------------+ | now() | +---------------------+ | 2014-01-22 15:55:47 | +---------------------+ 1 row in set (0.00 sec) +----+------+ | id | a | +----+------+ | 1 | 1 | | 2 | 22 | | 3 | 3 | +----+------+ 3 rows in set (0.00 sec) #数据被更新
写锁:
写锁和读锁的区别在于,当表被锁定之后,除非解锁,后面的会话进程(SESSION),什么事情也做不了,只能够等待解锁.
如何处理死锁(DeadLock)?
#执行以下命令 show processlist
未完,待续!