DROP TABLE IF EXISTS `student`;
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`stu_name` varchar(255) DEFAULT NULL,
`stu_age` int(11) DEFAULT NULL,
`stu_email` varchar(255) DEFAULT NULL,
`stu_height` double DEFAULT NULL,
`class_id` int(11) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=8 DEFAULT CHARSET=utf8;
--插入数据
BEGIN;
INSERT INTO `student` VALUES (1, '张三', 14, 'zhangsan@email', 180, 1);
INSERT INTO `student` VALUES (2, '李四', 15, 'lishi@', 152, 2);
INSERT INTO `student` VALUES (3, '王五', 17, '[email protected]', 177, 3);
INSERT INTO `student` VALUES (4, '赵六', 18, '[email protected]', 156, 4);
INSERT INTO `student` VALUES (5, '田七', 16, '[email protected]', 179, 2);
INSERT INTO `student` VALUES (6, '王八', 88, '[email protected]', 133, 3);
INSERT INTO `student` VALUES (7, '刘九', 34, '[email protected]', 193, 3);
COMMIT;
mysql> set autocommit=off;
Query OK, 0 rows affected (0.00 sec)
--查看数据
mysql> select * from student;
+----+----------+---------+-----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+-----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 180 | 1 |
| 2 | 李四 | 15 | lishi@ | 152 | 2 |
| 3 | 王五 | 17 | wangwu@126.com | 177 | 3 |
| 4 | 赵六 | 18 | zhaoliu@126.com | 156 | 4 |
| 5 | 田七 | 16 | tianqi@126.com | 179 | 2 |
| 6 | 王八 | 88 | wangba@126.com | 133 | 3 |
| 7 | 刘九 | 34 | liujiu@163.com | 193 | 3 |
+----+----------+---------+-----------------+------------+----------+
--此时是只有主键索引
mysql> show index from student;
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| student | 0 | PRIMARY | 1 | id | A | 7 | NULL | NULL | | BTREE | | |
+---------+------------+----------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
--开启事物
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where class_id=2 for update;
+----+----------+---------+----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+----------------+------------+----------+
| 2 | 李四 | 15 | lishi@ | 152 | 2 |
| 5 | 田七 | 16 | tianqi@126.com | 179 | 2 |
+----+----------+---------+----------------+------------+----------+
2 rows in set (0.00 sec)
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where class_id=1 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
--此处可以查看到查询失败
可以得出结论:行锁是建立在索引字段的基础上,如果行锁定的列不是索引列则会升级为表锁,我这两个测试的查询条件有重复字段,其实用两个值来测试也是同样的效果。
主要测试两个方面:一是索引列的数据重复率过高的情况下;二是索引列数据重复率过低。
--创建索引
mysql> create index class_id_index on student(class_id);
Query OK, 0 rows affected (0.03 sec)
Records: 0 Duplicates: 0 Warnings: 0
--查看索引
mysql> show index from student;
+---------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+---------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
| student | 0 | PRIMARY | 1 | id | A | 7 | NULL | NULL | | BTREE | | |
| student | 1 | class_id_index | 1 | class_id | A | 7 | NULL | NULL | YES | BTREE | | |
+---------+------------+----------------+--------------+-------------+-----------+-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.01 sec)
mysql> select * from student;
+----+----------+---------+-----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+-----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 180 | 1 |
| 2 | 李四 | 15 | lishi@ | 152 | 1 |
| 3 | 王五 | 17 | wangwu@126.com | 177 | 1 |
| 4 | 赵六 | 18 | zhaoliu@126.com | 156 | 2 |
| 5 | 田七 | 16 | tianqi@126.com | 179 | 2 |
| 6 | 王八 | 88 | wangba@126.com | 133 | 2 |
| 7 | 刘九 | 34 | liujiu@163.com | 193 | 2 |
+----+----------+---------+-----------------+------------+----------+
--开启事物
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
--正常查询
mysql> select * from student where class_id=1 for update;
+----+----------+---------+----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 180 | 1 |
| 2 | 李四 | 15 | lishi@ | 152 | 1 |
| 3 | 王五 | 17 | wangwu@126.com | 177 | 1 |
+----+----------+---------+----------------+------------+----------+
3 rows in set (0.00 sec)
--开启事物
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
--由于索引列的数据重复过多,导致索引失效,从而造成session1的行锁升级为表锁至sessino2的查询失败
mysql> select * from student where class_id=2 for update;
ERROR 1205 (HY000): Lock wait timeout exceeded; try restarting transaction
结论:索引列数据重复过多情况下,会导致索引失效,行锁变表锁。
5.1 数据情况
mysql> select * from student;
+----+----------+---------+-----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+-----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 180 | 1 |
| 2 | 李四 | 15 | lishi@ | 152 | 11 |
| 3 | 王五 | 17 | wangwu@126.com | 177 | 2 |
| 4 | 赵六 | 18 | zhaoliu@126.com | 156 | 3 |
| 5 | 田七 | 16 | tianqi@126.com | 179 | 4 |
| 6 | 王八 | 88 | wangba@126.com | 133 | 33 |
| 7 | 刘九 | 34 | liujiu@163.com | 193 | 22 |
+----+----------+---------+-----------------+------------+----------+
5.2 创建session1查询数据
mysql> begin; --开启事物
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where class_id=1 for update; --查询数据锁定
+----+----------+---------+----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 180 | 1 |
+----+----------+---------+----------------+------------+----------+
1 row in set (0.00 sec)
5.3 创建session2查询数据
mysql> begin; --开启事物
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where class_id=2 for update; --查询数据
+----+----------+---------+----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+----------------+------------+----------+
| 3 | 王五 | 17 | wangwu@126.com | 177 | 2 |
+----+----------+---------+----------------+------------+----------+
1 row in set (0.00 sec)
发现二者在查询数据时互不干扰。
5.4 在session1 的事物基础内修改数据
mysql> begin;
Query OK, 0 rows affected (0.00 sec)
mysql> select * from student where class_id=1 for update;
+----+----------+---------+----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 180 | 1 |
+----+----------+---------+----------------+------------+----------+
1 row in set (0.00 sec)
--上面是session1的操作。
--修改数据
mysql> update student set stu_height=134 where class_id=1;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
--修改成功后的结果
mysql> select * from student where class_id=1;
+----+----------+---------+----------------+------------+----------+
| id | stu_name | stu_age | stu_email | stu_height | class_id |
+----+----------+---------+----------------+------------+----------+
| 1 | 张三 | 14 | zhangsan@email | 134 | 1 |
+----+----------+---------+----------------+------------+----------+
1 row in set (0.00 sec)
总结:
上述sql 中的 for update 是给当前语句加上排他锁
来源:https://www.cnblogs.com/zyy1688/p/9983122.html