mysql事务:并发事务有哪些问题?

事务

什么是事务

事务是一个不可分割的、独立的执行单元,一个事务内的语句要么全部执行,要么全部不执行。

事务的特性

  • 原子性:事务是不可分割的最小的工作单元,只有完全执行或完全不执行两种执行逻辑。
  • 一致性:数据库总是从一个执行状态转换到另一个一致性状态。
  • 隔离性:通常来说,一个事务在提交修改前,对其他事务是不可见的。
  • 持久性:一旦事务已提交,其所做的更改就会永久保存到数据库中。

事务的隔离级别

数据库事务的隔离性是指数据库系统必须具有隔离并发运行各个事务的能力, 使它们不会相互影响, 避免各种并发问题。

一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔 离级别, 不同隔离级别对应不同的干扰程度, 隔离级别越高, 数据一致性就 越好, 但并发性越弱.

隔离级别种类

隔离级别描述备注
READ UNCOMMITTED允许事务读取未被其他事务提交的变更,脏读、不可重复度和幻读的问题都会出现读未提交
READ COMMITTED只允许事务读取已经被其它事务提交的变更.可以避免脏读,但不可重复读和幻读问 题仍然可能出现Oracle 默认:读已提交
REPEATABLE READ确保事务可以多次从一个字段中读取相同的值.在这个事务持续期间,禁止其他事物 对这个字段进行更新.可以避免脏读和不可重复读,但幻读的间题仍然存在mysql 默认:可重复读
SERIALIZABLE确保事务可以从一个表中读取相同的行.在这个事务持续期间,禁止其他事务对该表 执行插入,更新和删除操作.所有并发问题都可以避免,但性能十分低下相当于锁表, 串行
  • 比较

    • 安全性来说:Serializable>Repeatable read>Read committed>Read uncommitted
    • 效率来说:Serializable<Repeatable read<Read committed<Read uncommitted

通常来说,一般的应用都会选择Repeatable readRead committed作为数据库隔离级别来使用。

查看事务的隔离级别

  • mysql 8.0
SELECT @@transaction_isolation;

在这里插入图片描述

  • mysql 5.0
SELECT @@tx_isolation;
  • 通用
show variables  like '%isolation%';

设置隔离级别

  • serializable
set session transaction isolation level serializable;
  • read committed
set session transaction isolation level read committed;
  • read uncommitted
set session transaction isolation level read uncommitted;
  • repeatable read
set session transaction isolation level repeatable read;

session:表示当前会话级别,如果是全局,则换成 global即可。

事务的使用

  • 事务的分类:隐式事务和显示事务。

隐式事务

没有明显的开启和结束事务的标志,比如 insert、update、delete语句本身就是一个事务

显式事务

具有明显的开启和结束事务的标志

  • 步骤1、开启事务:取消自动提交事务的功能
set autocommit=0;
start transaction;#可选的
  • 步骤2、编写事务的一组逻辑操作单元(多条sql语句)
insert、update、delete
  • 步骤 3、提交事务或回滚事务,此次事务操作结束。
commit;

rollback;

演示表

创建表

create table if not exists students
(
    id      int,
    name    varchar(20),
    balance decimal(10, 2)
);

插入测试数据

 insert into students values (1, '张三', 1000);

并发对事物的影响

并发会造成事务间出现 脏读、不可重复度、覆盖、幻读现象。

对于同时运行的多个事务, 当这些事务访问数据库中相同的数据时, 如果没 有采取必要的隔离机制, 就会导致各种并发问题。

脏读

是一个事务在处理过程中读取了另外一个事务未提交的数据。

对于两个事务 T1、T2, T1 读取了已经被 T2 更新但还没有被提交的字段. 之后, 若 T2 回滚, T1读取的内容就是临时且无效的,T1 读到的这个数据就是脏数据。

不可重复读

指在一个事务内多次读取同一数据,在这个事务还没结束时,另外一个事务也访问了这个数据并对这个数据进行了修改,那么就可能造成第一个事务两次读取的数据不一致,这种情况就被称为不可重复读

对于两个事务T1, T2, T1 读取了一个字段, 然后 T2 更新了该字段. 之后, T1再次读取同一个字段, 值就不同了.

幻读

是指同一个事务内多次查询返回的结果集总数不一样(比如增加了或者减少了行记录)。

对于两个事务T1, T2, T1 从一个表中读取了一个字段, 然后 T2 在该表中插 入了一些新的行. 之后, 如果 T1 再次读取同一个表, 就会多出几行。

脏读演示

执行顺序转账事务1转账事务2
T1开始事务
T2读取账户余额1000元开始事务
T3存款100 元,修改账户余额 1100 元(1000+100)读取账户余额:1100 元(脏读)
T4事务结束:撤销事务,数据回滚到 1000 元存款400 元,修改账户余额 1400 元(1000+400)
T5事务结束:提交事务

开启两个终端,分别登录数据库

在这里插入图片描述

设置事务的隔离级别为读未提交

set session transaction isolation level read uncommitted;

在这里插入图片描述

查看数据库

show databases;

在这里插入图片描述

选择测试数据库

use my_demo;
select * from students;

表中只有一条测试数据

+------+--------+---------+
| id   | name   | balance |
+------+--------+---------+
|    1 | 张三   | 1000.00 |
+------+--------+---------+
1 row in set (0.01 sec)

开启事务

两个终端都开启事务

start transaction;

查询余额

select balance from students where id=1;
+---------+
| balance |
+---------+
| 1000.00 |
+---------+
1 row in set (0.01 sec)

事务 1修改余额

update students set balance=balance+100 where id=1;

事务 2 查询余额

select balance from students where id=1;

在这里插入图片描述

  • 此时如何事务 2 执行更新操作也会阻塞。

在这里插入图片描述

事务1 执行回滚,之后,在事务 2窗口 执行更新操作

  • 在事务 1 回滚后,事务 2 不要再次查询余额,否则演示就没有意义了。
rollback

事务 1 回滚之后,事务 2 执行更新操作

update students set balance=balance+400 where id=1;

在这里插入图片描述

不可重复读演示

基于脏读案例,事务 1 继续查询,发现数据与回滚前不一致了,数据被其他进程修改了,这就是不可重复读现象。

事务 1查询余额,发现与上次不一致了

此时发现余额为1400,这就是事务 2 在食事务 1 为执行完读取了事务1 修改而未提交的数据导致的。也就是事务隔离级别为 可读未提交导致的。

+---------+
| balance |
+---------+
| 1400.00 |
+---------+
1 row in set (0.01 sec)

在这里插入图片描述

错误演示说明

  • 下图为事务 1 回滚后,事务 2 再次查询余额,结果两个事务数据是一致的
  • 这里为了演示,事务 2 只在事务 1 更新以后,回滚之前,做一次查询操作。

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值