数据库事务入门

场景

我们拿经典的转账场景来说明事务是什么

现在有这么一个场景, 银行系统中有一个A账户和一个B账户, A账户和B账户中都有1000元, A账户想要给B账户转账100元, 包括以下两个操作:

  1. A账户扣除100元
  2. B账户增加100元

理想情况下, 上面的操作1和操作2都成功了, A账户扣除100元, 最终为900元, B账户增加100元, 最终为1100元. 但是, 在现实场景中有很多失败的情况, 比如操作1成功了, 操作2失败, 这个时候A账户扣除100元, 最终为900元, B账户却没有增加100元, 还是为1000元. 这个时候数据就不一致了

事务是为了解决什么

事务就是为了解决上面这种数据一致性问题

当我们需要执行一系列操作时, 理论上, 每一个操作都有可能执行成功或者失败, 那么最终结果的可能性就会有很多, 数据的一致性得不到保障
多个操作执行结果
为了解决这种数据不一致问题, 我们把多个操作封装起来, 称为一个事务. 这个事务的执行结果只有两种, 执行成功或者执行失败, 不存在部分成功, 部分失败的情况, 这样就保证了数据的一致性
在这里插入图片描述

事务的定义

事务就是把一系列操作(在数据库中通常表现为一系列SQL)封装成一个不可分割的工作单元, 一个事务中的操作要么全部执行成功, 要么全部执行失败, 不存在部分成功, 部分失败

事务的四大特征

一致性

事务出现的原因就是为了解决数据的一致性问题. 针对上面转账的场景, A账户向B账户转账100元, 保证A账户扣除100元, B账户增加100元, 不会出现部分成功, 部分失败的情况, 也就是保证数据的一致性

原子性

事务是一个最小的工作单元, 事务中的所有操作要么全部执行成功, 执行失败, 不存在部分成功, 部分失败

mysql数据库innodb存储引擎通过undo log保证事务的原子性

持久性

一个事务的操作在提交成功后, 对数据的修改就是永久性的, 即使服务器发生故障, 故障恢复后数据也不会丢失

mysql数据库innodb存储引擎通过redo log保证事务的持久性

隔离性

一个事务的执行不能被其他事务干扰, 即事务的执行是隔离的, 并发执行的各个事务之间不能互相干扰

事务的隔离级别

读未提交

A事务在执行过程中, 读取到了B事务未提交修改的数据

B事务后来后能提交失败了, 事务进行了回滚, 这个时候可能出现脏读
在这里插入图片描述

读已提交

A事务在执行过程中, 读取到了B事务已提交修改的数据

A事务在执行过程中, 第一次读取到的是B事务已提交修改的数据a1, 第二次读取到的是C事务已提交修改的数据a2, 这个时候A事务前后两次读取的数据a可能不一样, 即不可重复读
在这里插入图片描述

可重复读

A事务在事务内重复读取数据a, 此时不管别的事务对数据a进行了update还是delete, A事务内多次读取数据a的结果是一致的

但是, 如果此时B事务对数据a进行了insert操作, 那么A事务还是能够读取到insert的新数据, 造成多次读取数据a前后不一致, 这种现象我们称之为幻读

mysql数据库innodb存储引擎默认的隔离级别就是可重复读, 并且解决了幻读
在这里插入图片描述

串行化

事务串行执行, 解决了脏读, 不可重复读, 幻读问题. 但是, 因为是串行执行, 执行效率很低, 极大的降低了处理并发的能力

可重复读和幻读的区别

从总的结果来看, 两者都表现为两次读取的结果不一致

两者的重点不一样:

  • 可重复读: 重点在于update和delete情况下, 保证可重复读
  • 幻读: 重点在于insert, 这种情况下可重复读还是会出现幻读现象

从加锁的角度来看, 两者的区别就很明显:

  • 可重复读: 行锁, 把满足条件的行锁住就行
  • 幻读: 行锁+间隙锁,需要把满足条件的行和间隙都锁住

总结来说, 可重复读和幻读最大的区别, 就是如何通过锁的机制来解决问题

Mysql事务处理

准备

# 输入密码登录mysql
mysql -u root -p

# 查看已有的数据库
show databases;

# 创建一个数据库
create database flight;

# 使用数据库
use flight;

# 创建一张表
create table user (
    id bigint auto_increment primary key,
    name varchar(100)
);

事务演示

简单事务

mysql中的简单事务处理主要有以下几步:

  1. 使用begin或者start transaction显示开启一个事务
  2. 执行成功, 使用commit提交事务
  3. 执行失败, 使用rollback回滚事务
# 开启一个事务
begin;
# 查看表里面的数据,这个时候表里面没有数据
select * from user;
# 插入一条数据
insert into user(name) value("tom");
# 查询,这个时候表里面有一条{id:1,name:"tom"}的记录
select * from user;
# 事务回滚
rollback;
# 这个时候表里面没有数据
select * from user;

事务嵌套

mysql的事务支持嵌套, 可以只回滚指定的嵌套事务, 外层事务不受影响, 实现步骤:

  1. savepoint pointName - 设置一个保留点
  2. rollback to pointName - 指定回滚到具体的保留点, 实现嵌套事务的回滚

保留点在事务处理完成(执行一条rollback或commit)后自动释放, 也可以通过release savepoint pointName来删除指定保留点

# 开启一个事务
begin;
# 查看表里面的数据,这个时候表里面没有数据
select * from user;
# 插入一条数据
insert into user(name) value("tom1");
# 查询,这个时候表里面有一条{id:2,name:"tom1"}的记录
# 注意,这个时候id变为2了,虽然之前的事务回滚了,id还是自增长了
select * from user;
# 嵌套事务,使用保留点
savepoint point1;
# 插入一条数据
insert into user(name) value("tom2");
# 查询,这个时候表里面有两条记录
# [{id:2,name:"tom1"},{id:3,name:"tom2"}]
select * from user;
# 回滚到指定保留点,可以实现嵌套事务的回滚
rollback to point1;
# 提交事务
commit;
# 查询, 这个时候表里面有一条{id:2,name:"tom1"}的记录, 因为嵌套事务回滚了
select * from user;

事务自动提交

查看事务自动提交开关

show variables like 'autocommit';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| autocommit    | ON    |
+---------------+-------+

autocommit的值为ON, 表示开启了事务自动提交

autocommit的值为OFF, 表示关闭了事务自动提交

在mysql中, 可以通过set autocommit来设置事务自动提交开关

# 关闭事务自动提交, 两种方式都可以
set autocommit = 0;
set autocommit = OFF;

# 开启事务自动提交, 两种方式都可以
set autocommit = 1;
set autocommit = ON;

开启事务自动提交

如果开启自动提交, 则每执行一条sql语句, 事务都会提交一次

也就是mysql会在每条被执行的sql后面, 自动执行commit操作, 然后开启一个新的事务

使用begin或者start transaction显式开启一个事务之后, 开启事务自动提交会被禁用, 等到执行了commit或者rollback之后, 结束了本次事务, 自动提交开关才会生效

关闭事务自动提交

关闭自动提交后, 会从该位置后开启一个新的事务, 直到手动执行了commit或者rollback语句之后(如果是终止了mysql会话, 也会自动执行rollback)当前事务结束, 开启一个新的事务

# 关闭事务自动提交
set autocommit = 0;

# 插入一条数据
insert into user(name) value("tom3");

# 显式开启一个事务
begin

# 插入一条数据
insert into user(name) value("tom4");

# 会把从set autocommit = 0位置后到commit之前的sql都进行提交
commit;

# commit之后, 已经开启了一个新的事务, 所以这个地方的回滚没有效果
rollback;
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值