Mysql事务

Posted 水月情缘雪飞飞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Mysql事务相关的知识,希望对你有一定的参考价值。

@[TOC]mysql事务

简介

事务四大特征(ACID)

推荐: https://blog.csdn.net/lianghecai52171314/article/details/102782804

原子性:事务是最小单位,不可再分,例如:update … insert … delete …

一致性:所有的DML语句操作,必须同时成功或者同时失败

隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read
committed)、可重复读(repeatable read)和串行化(Serializable)。

持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

事务的4个级别

隔离级别:

隔离级别脏读(Dirty Read)不可重复读(NonRepeatable Read)幻读(Phantom Read)
未提交读(READ-UNCOMMITTED)
已提交读(READ-COMMITTED)
可重复读(REPEATABLE-READ)[默认级别]
串行化(SERIALIZABLE )

脏读,幻读,不可重复读

脏读[脏数据](Dirty Read): 两个事务,一个事务未提交的数据(commit),另一个事务可以读取到.

不可重复读(NonRepeatable Read):事务A在修改数据,事务B在事务A 数据(修改前)和(修改后),未提交(commit)前,两次读取的数据不一致。

幻读(Phantom Read):是指多个事务执行时发生的一种现象。事务A新增或删除了数据,但是未提交(commit),事务B发现新增或删除的数据,就像幻觉一样。

备注

不可重复读的重点是修改:

同样的条件,你读取过的数据,再次读取出来发现值不一样了

幻读的重点在于新增或者删除:

同样的条件,第 1 次和第 2 次读出来的记录数不一样

查询与设置隔离级别

查询会话事务级别

# mysql 查询会话级别
select @@transaction_isolation; # 查询当前的会话事务级别 
select @@global.transaction_isolation; # 查询全局的事务隔离级别
show variables like 'transaction_isolation';


# 8.0以下版本,8.0之后版本废弃
select @@tx_isolation;  # 查询当前的会话事务级别 
select @@global.tx_isolation; # 查询全局的事务隔离级别

+-----------------+
| @@tx_isolation  |
+-----------------+
| REPEATABLE-READ |
+-----------------+

设置事务级别

# 未提交读  read uncommitted级别:
set session transaction isolation level read uncommitted;

# 已提交读 read committed级别:
set session transaction isolation level read committed;

# 可重复读 repeatable read级别:
set session transaction isolation level repeatable read;

# 可串行化 serializable级别:
set session transaction isolation level serializable;

# 开始事务
begin; 
start transaction; 
# 提交事务
commit; 
# 回滚
rollback;   

示例测试数据

初始化数据表

-- 登录mysql
-- mysql -u root -h 127.0.0.1 -p

-- 创建数据库
-- create database testdb;

use testdb;
drop table if exists user;
CREATE TABLE `user`(
    `id`   int(11) unsigned NOT NULL AUTO_INCREMENT,
    `name` varchar(255) NOT NULL DEFAULT '' COMMENT '名字',
    `num`  int(11) NOT NULL DEFAULT 0 COMMENT '数量',
    PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

-- 初始数据
INSERT INTO `user` (`name`,`num`) VALUES ('one',0),('two',0),('three',0);

select * from user;
+----+-------+-----+
| id | name  | num |
+----+-------+-----+
|  1 | one   |   0 |
|  2 | two   |   0 |
|  3 | three |   0 |
+----+-------+-----+

未提交读

事务A事务B
无事务
备注
set session transaction isolation level read uncommitted;

begin;


设置事务级别
开启事务

set session transaction isolation level read uncommitted;

begin;
set session transaction isolation level read uncommitted;

select * from user; 

idnamenum
1one0
2two0
3three0



原始数据

INSERT INTO `user` (`name`,`num`) VALUES ('four',0);


UPDATE user SET num=10 where id=1;


DELETE FROM user where id=3;


select * from user;

idnamenum
1one10
2two0
4four0






select * from user; 

idnamenum
1one10
2two0
4four0

脏读

事务A数据未提交但是事务B可以读取




select * from user; 

idnamenum
1one10
2two0
4four0


虽然未启用事务,但是依然课读取到脏数据

commit; (事物提交)

idnamenum
1one10
2two0
4four0




rollback; (事物回滚,无操作)

idnamenum
1one10
2two0
4four0




select * from tb;

idnamenum
1one10
2two0
4four0

已提交读

事务A事务B
无事务
备注
set session transaction isolation level read committed;

begin;
set session transaction isolation level read committed;

begin;
set session transaction isolation level read committed;设置事物级别
开启事物

select * from user; 

idnamenum
1one0
2two0
3three0


INSERT INTO `user` (`name`,`num`) VALUES ('four',0);


UPDATE user SET num=10 where id=1;


DELETE FROM user where id=3;


select * from user;

idnamenum
1one10
2two0
4four0






select * from user; 

idnamenum
1one0
2two0
3three
0

看不见事务A数据修改



select * from user; 

idnamenum
1one0
2two0
3three0



commit; (事物提交)


idnamenum
1one10
2two0
4four0


事物A提交

select * from user; 

idnamenum
1one10
2two0
4four0



不可重复读,

数据被修改,读取到已提交的数据。


幻读(一种现象),

第一次查询可以看见3,第二次查询3被删除,查询到了4,行不一样了


rollback; (事物回滚,无操作)





select * from user; 

idnamenum
1one10
2two0
4four0

可重复读

事务A事务B
无事务
备注
set session transaction isolation level repeatable read;

start transaction;
set session transaction isolation level repeatable read;

start transaction;
set session transaction isolation level repeatable read;设置事物级别
开启事物


select * from user; 

idnamenum
1one0
2two0
4four0


INSERT INTO `user` (`name`,`num`) VALUES ('four',0);


UPDATE user SET num=10 where id=1;


DELETE FROM user where id=3;


select * from user;

idnamenum
1one10
2two0
4four0






select * from user; 

idnamenum
1one0
2two0
3three
0

看不见数据修改



select * from user; 

idnamenum
1one0
2two0
3three0



commit; (事物提交)


idnamenum
1one10
2two0
4four0




select * from user; 

idnamenum
1one0
2two0
3three0



未查询到修改,避免 不可重复读取 ,


UPDATE user SET num=num+20 where id=1;


select * from user; 

idnamenum
1one30
2two0
3three0



更新后id=1的值为30,


在可重复读的隔离级别下,MySQL采用的是MVCC机制,select 操作不会更新版本号,是快照读(历史版本);而insert、update和delete会更新版本号,是当前读(当前版本)


commit; (事务提交)

idnamenum
1one30
2two0
4four0

结束后发现最新数据


select * from user; 

idnamenum
1one30
2two0
4four0

串行化

事务A事务B
无事务
备注
set session transaction isolation level serializable;

start transaction;
set session transaction isolation level serializable;

start transaction;
set session transaction isolation level serializable;设置事物级别
开启事物

INSERT INTO `user` (`name`,`num`) VALUES ('four',0);


UPDATE user SET num=10 where id=1;


DELETE FROM user where id=3;


select * from user;

idnamenum
1one10
2two0
4four0






select * from user; 


等待 事物A 执行。。。






select * from user; 

idnamenum
1one0
2two0
3three0



commit; (事物提交)


idnamenum
1one10
2two0
4four0




事物A 等待结束,开始执行语句。。。

idnamenum
1one10
2two0
4four0



最新数据


rollback; (事物回滚,无操作)

idnamenum
1one10
2two0
4four0




select * from user; 

idnamenum
1one10
2two0
4four0

以上是关于Mysql事务的主要内容,如果未能解决你的问题,请参考以下文章

事务的隔离级别和传播特性

事务的传播行为,隔离级别以及锁机制

PHP 与 MYSQL 在计算时,为啥会出现这样的数字,

知道现值,年金,求利率?

已知年金和现值求利率的问题

第五章 投资项目资本预算