数据库MySQL动手模拟四种隔离级别(要两个客户机)
以Navicat为客户机A,cmd终端为客户机B
首先要有个数据库和表
打开客户机A
-- 首先要有个数据库
create database company;
use company;
-- 首先要有个表
#建立account表
CREATE TABLE account(
account_no INT AUTO_INCREMENT PRIMARY KEY,
account_name VARCHAR(10) NOT NULL,
balance INT UNSIGNED #balance不能取负值
);
#向account表插入记录
INSERT INTO account VALUES(null,'李三',1000);
INSERT INTO account VALUES(null,'王五',1000);
动手模拟
脏读现象
读脏数据也称为读未提交的数据 。
原因:由于后一事务读了前一个事务写了但尚未提交的数据引起,称为写—读冲突。
结果:读到有可能要回退的更新数据。
-- 打开MySQL客户机A,执行下面语句。
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT @@transaction_isolation;
START TRANSACTION; #开始事务
SELECT * FROM account;
现在客户机A上account表
cmd终端管理员权限打开,作为客户机B
->要先转到bin文件夹
->root登录
#显示所有的数据库
show databases;
#在新建的数据库company中创建新用户tempuser
#password:123
#并授予所有权限
CREATE USER 'tempuser'@'localhost' IDENTIFIED BY '123';
GRANT ALL PRIVILEGES ON company.* TO tempuser@localhost with grant option; #创建用户时显示localhost,grant时也要显示
show grants for tempuser@'loaclhost'; #@前不加''@后加
#登录tempuser
SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
SELECT @@transaction_isolation;
START TRANSACTION;
#cmd中要先
USE company;
UPDATE account SET balance=balance+1000 WHERE account_no=1;
然后再打开客户机A
SELECT * FROM account;
MySQL客户机A看到了MySQL客户机B尚未提交的更新结果,造成脏读现象。
客户机A在窗口直接打开account表,由于两个客户机的事务都没有提交,所以,account表中的数据没有变化,'李三’账户的余额仍然是200。
不可重复读现象
-- 为防止上一个模拟影响本次模拟,打开MySQL客户机B,执行下面语句。
ROLLBACK;
-- 打开MySQL客户机A,执行下面语句。
SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
SELECT @@transaction_isolation;
START TRANSACTION;
SELECT * FROM account;
-- 打开MySQL客户机B,执行下面语句。
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
START TRANSACTION;
UPDATE account SET balance=balance+1000 WHERE account_no=1;
COMMIT;
-- 打开MySQL客户机A,执行下面语句。
SELECT * FROM account;
MySQL客户机A在同一个事务中两次执行“SELECT * FROM account;”的结果不相同,造成不可重复读现象。
幻影读现象
-- 打开MySQL客户机A,执行下面语句。
SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ;
SELECT @@transaction_isolation;
set autocommit = 0; # 将自动提交设置为0 不进行自动提交 自动提交将看不到效果 最好两个事务都开启
START TRANSACTION;
SELECT * FROM account;
-- 打开MySQL客户机B,执行下面语句。
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;
START TRANSACTION;
INSERT INTO account VALUES(10,'赵六',3000);
COMMIT;
SELECT * FROM account;
-- 打开MySQL客户机A,执行下面语句。
SELECT * FROM account;
#由于MySQL客户机A检测到account表中不存在account_no=10的账户信息,在MySQL客#户机A继续执行下面INSERT语句。
INSERT INTO account VALUES(10,'赵六',3000);
运行结果显示account表中确实存在account_no=10的账户信息,但由于REPEATABLE READ(可重复读)隔离级别使用了“障眼法”,使得MySQL客户机A无法查询到account_no=10的账户信息,这种现象称为幻影读现象。
说明:幻影读和不可重复读现象不同之处在于,幻影读现象读不到其他事务已经提交(COMMIT)的行数据,而不可重复读现象读到的是其他事务已经提交(COMMIT)的数据。
避免幻影读现象
-- 打开MySQL客户机A,执行下面语句。
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT @@transaction_isolation;
START TRANSACTION;
SELECT * FROM account;
-- 打开MySQL客户机B,执行下面语句。
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE;
START TRANSACTION;
INSERT INTO account VALUES(20,'马七',5000);
SELECT * FROM account;
-- 打开MySQL客户机B,执行下面语句。
SET SESSION TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT @@transaction_isolation;
START TRANSACTION;
INSERT INTO account VALUES(20,'马七',5000);
由于发生了锁等待超时引发的错误异常,事务被回滚,所以account_no=20的账户信息并没有添加到account表中。