结论
如果不显式写transaction, 在innodb下,每一条语句都是事务,可以通过set autocommit = 0 (默认值1,不需要手动添加开始事务和提交语句),设置当前会话手动提交,一般需要执行多条语句的时候,就会显式地开始事务。
如果以start transction; 开头,后面添加sql语句,则在提交,即commit之前,修改的脏数据都会被存放在bufferPool中,而磁盘中的数据会被锁定,无法被更改。
实验过程
1. 使用docker搭建实验环境
[root@localhost cenos7]# service docker start
Redirecting to /bin/systemctl start docker.service
[root@localhost cenos7]# docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
9cb5bc55c6e9 zookeeper "/docker-entrypoint.…" 2 days ago Exited (0) 8 seconds ago 2888/tcp, 3888/tcp, 8080/tcp, 0.0.0.0:2182->2181/tcp, :::2182->2181/tcp zk02
ecf9251168cd zookeeper "/docker-entrypoint.…" 2 days ago Exited (0) 8 seconds ago 2888/tcp, 3888/tcp, 0.0.0.0:2181->2181/tcp, :::2181->2181/tcp, 8080/tcp zk01
a170d5f3a7f3 mysql:5.6 "docker-entrypoint.s…" 2 months ago Exited (137) 2 days ago c_mysql
[root@localhost cenos7]# docker start c_mysql
c_mysql
[root@localhost cenos7]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a170d5f3a7f3 mysql:5.6 "docker-entrypoint.s…" 2 months ago Up 7 seconds 0.0.0.0:3307->3306/tcp, :::3307->3306/tcp c_mysql
注意:0.0.0.0:3307->3306的意思是:当前虚拟机的IP的3307号端口,映射到了DOCKER容器的3306号端口,即,可以通过虚拟机ip:3307访问到mysql容器。
2. 创建会话
本人使用SQLyog创建两个会话。
3. 隔离性实验
默认提交事务
不表明transaction, 则每次执行完SQL语句后就自动提交事务。
在会话1中执行如下语句:
DROP TABLE IF EXISTS user_profile;
CREATE TABLE user_profile(
id INT NOT NULL,
device_id INT NOT NULL,
gender VARCHAR(14) NOT NULL,
age INT,
university VARCHAR(36) NOT NULL,
province VARCHAR (32) NOT NULL)
ENGINE = INNODB CHARSET = utf8
;
INSERT INTO user_profile
VALUES(1,2138,'male',21,'北京大学','BeiJing');
INSERT INTO user_profile
VALUES(2,3212,'male',NULL,'复旦大学','shanghai');
INSERT INTO user_profile
VALUES(3,3422,'female',20,'北京大学','Beijing');
INSERT INTO user_profile
VALUES(4,6534,'female',23,'浙江大学','ZheJiang');
INSERT INTO user_profile
VALUES(5,8523,'male',25,'山东大学','Shangdong');
在会话2中执行
SELECT * FROM `user_profile`;
查询结果:
显式执行事务
在会话1中执行:
START TRANSACTION;
UPDATE `user_profile` SET age = 1024 WHERE id = 2;
结果显示
在当前事务下继续执行
SELECT age FROM `user_profile` WHERE id = 2;
在会话2中执行
START TRANSACTION;
SELECT * FROM `user_profile` WHERE id = 2;
结果还是初始的NULL值
如果在会话2中尝试更改id=2的数值,会被阻塞,知道会话1事务提交,才能执行成功。