mysql的事务简介、事务特性及隔离级别详解代码示例
1.什么是事务
- 所谓的事务就是针对数据库的一组操作。他可以由一条或者多条sql语句组成,同一个事务的操作具备同步的特点,即事务中的语句要么都执行,要么 都不执行。
2.事务的使用
- 开启事务-> start transaction
- 执行sql
- 提交事务 commit
- 取消事务(回滚) rollback
- 示例
--创建一个employee表
drop table employee;
create table employee(
eid int primary key auto_increment,
ename varchar(20) not null,
balance double(9,2) check(balance>0)
);
--插入几条数据
insert into employee(ename,balance) values('小明',8000);
insert into employee(ename,balance) values('小红',9000);
insert into employee(ename,balance) values('李华',10000);
select * from employee;
--创建事务
start transaction;
insert into employee(ename,balance) values('a',6500);
insert into employee(ename,balance) values('b',7800);
##此时事务尚未被提交,但是employee表已经插入上去数据了,数据可以被回退或者提交
##提交
commit;
3.事务的特性
四个特性
-
原子性
- 原子性是指一个事务必须被视为一个不可分割的最小的工作单元,只有事务的所有的数据库操作都执行成功才算整个事务执行成功
-
一致性
- 一致性是指事务将数据库从一种状态转变为下一种一致的状态(例如转账前转账后总金额不发生改变)
-
隔离性
- 隔离性还可以被称为并发控制、可串行化、锁等,当多个数据库为每一个用户开启事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离
-
持久性
- 持久性是指事务一旦被提交,其所作的修改就会永久的保存在数据库中,即使数据库发生故障也不应该对其有任何影响。
- 事务的持久性不能做到100%的持久,只能从事务本身的角度来保证永久性,而一些外部原因导致数据库发生故障,如硬盘损坏,那么所有提交的数据可能都会丢失。
4.事务的隔离级别
- 读未提交(read-uncommitted)
- 不可重复读(read-committed)
- 可重复读(repeatable-read)
- 串行化(serializable)
由于不同的隔离级别会引发不同的并发问题
-
脏读
-
事务A读取了事务B更新的数据,然后B回滚操作,那么A读取的数据 是脏数据。
-
代码示例
-
##事务B
start transaction;
update employee set balance=10000 where eid=1;
##事务A
select * from employee where eid=1; ##脏数据
##事务B
rollback;
-
不可重复读
-
事务A多次读取同一数据,事务B在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果不一样
-
代码示例
-
##事务A
select * from employee where eid=1; ##第一次读取数据
##事务B
start transaction;
update employee set balance=10000 where eid=1;
commit;
##事务A
select * from employee where eid=1; ##第二次读取数据,发现与第一次读取的数据不同
-
幻读
-
系统管理员将数据库中所有的学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体的分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
-
代码示例
-
#准备工作
create table score1(
sid int primary key auto_increment,
sname varchar(20) not null,
point varchar(20) not null
);
insert into score1(sname,point) values('小明','80');
insert into score1(sname,point) values('小红','90');
insert into score1(sname,point) values('张三','100');
insert into score1(sname,point) values('张三','70');
insert into score1(sname,point) values('李四','60');
#开始
select * from score1;
系统管理员A
update score1 set point='A' where point='100';
update score1 set point='B' where point='90';
update score1 set point='C' where point='80';
update score1 set point='D' where point='70';
update score1 set point='E' where point='60';
系统管理员B
insert into score1(sname,point) values('小红','90');
系统管理员A
select * from score1;
-
注意区分 不可重复读和幻读 不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需要锁住满足条件的行,解决幻读需要锁表。
-
mysql事务隔离级别的作用
| 事务隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| 读未提交 | 是 | 是 | 是 |
| 不可重复读 | 否 | 是 | 是 |
| 可重复读 | 否 | 否 | 是 |
| 串行化 | 否 | 否 | 否 |
- InnoDB默认级别 可重复读
读未提交 代码示例(根据序号执行)
- 打开客户端A,并设置当前的事务隔离级别为读未提交,查询employee表的数据
##客户端A
##设置事务级别为读未提交
#①
set session transaction isolation level read uncommitted;
##开启事务
#②
start transaction;
#③
select * from employee;
#数据如下
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
#⑥
select * from employee;
#数据如下
1 小明 5000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
#⑧
select * from employee;
#数据如下
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##客户端B
##设置事务的级别
#④
set session transaction isolation level read uncommitted;
start TRANSACTION;
##更新数据
#⑤
update employee set balance=5000 where eid=1;
#⑦
rollback;
读已提交 代码示例(根据序号执行)
##客户端A
#①设置事务级别为读已提交
set session transaction isolation level read committed;
##开启事务
start transaction;
##③查询数据
select * from employee;
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##⑦查询数据(查询不到事务B更新的数据,解决了脏读的问题)
select * from employee;
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##⑨查询数据(上下结果不一致,产生了不可重复读的问题)
select * from employee;
1 小明 5000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##客户端B
#④设置事务的级别
set session transaction isolation level read committed;
##⑤开启事务
start transaction;
#⑥更新employee表
update employee set balance=5000 where eid=1;
#⑧事务提交
commit;
可重复读 代码示例(根据序号执行)
##客户端A
#①设置事务级别为可重复读
set session transaction isolation level repeatable read;
##②开启事务
start transaction;
##③查询数据
select * from employee;
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##⑦查询数据(查询不到事务B更新的数据,解决了脏读的问题)
select * from employee;
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##⑨查询数据(上下结果一致,解决了不可重复读的问题)
select * from employee;
1 小明 10000.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##⑩更新数据(更新数据却是用的客户端B的 (9950-50) )
update employee set balance=balance-50 where eid=1;
select * from employee;
1 小明 9900.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,
select操作不会更新版本号,是快照读(历史版本);
insert、update和delete会更新版本号,是当前读(当前版本)。
##12查询(没有查到新插入的数据)
select * from employee;
1 小明 9900.00
2 小红 9000.00
3 李华 10000.00
4 a 6500.00
5 b 7800.00
##客户端B
#④设置事务的级别
set session transaction isolation level repeatable read;
##⑤开启事务
start transaction;
#⑥更新employee表
update employee set balance=balance-50 where eid=1;
select * from employee;
#⑧事务提交
commit;
##客户端B
# 11 设置事务的级别
set session transaction isolation level repeatable read;
##开启事务,插入数据
start transaction;
insert into employee(ename,balance) values('hhh',5000);
串行化 (代码示例)
##客户端A
#①设置事务级别为串行化
set session transaction isolation level SERIALIZABLE;
##②开启事务
start transaction;
##③查询数据
select * from employee;
##客户端B
#①设置事务级别为串行化
set session transaction isolation level SERIALIZABLE;
##②开启事务
start transaction;
##③插入查询数据
insert into employee(ename,balance) values('111',5000);
select * from employee;
串行化由于并发性极低,开发中很少会用到。

浙公网安备 33010602011771号