【MySQL篇】事务的认识以及四大特性

何为事务?

事务(Transaction)是指一组操作的集合,这些操作要么全部执行成功,要么全部不执行。事务通常用于保证数据库的一致性、完整性和可靠性,确保数据的完整性与正确性。

有效避免部分执行,部分未执行而引起的问题;

引入例子:

假设以下场景: 转账
第一步A用户转账给B用户100元 账户-100

sql 复制代码
-- 从账户A扣款
UPDATE accounts SET balance = balance - 100 WHERE account_id = 'A';

第二步B用户收到A转账100元 账户+100

sql 复制代码
-- 向账户B存款
UPDATE accounts SET balance = balance + 100 WHERE account_id = 'B';

此时如果第一步完成之后,由于受到各种原因,例网络波动,主机关机,MySQL服务器崩溃等等因素,导致第二步未操作,这可损失大了,A凭空丢失100,所以这种情况是不允许发生的。

此时由于是俩个操作,所有MySQL会将这俩个操作打包成一个操作(原子性),要么一起完成,要么都不完成。

如果中途发生异常,此时操作将会进行"回滚"操作,所有操作将会被撤销。

补充:MySQL会将每一步操作都会记录在MySQL的日志中,所以可以根据日志里面的内容进行还原操作

在 MySQL 中,事务是由多个 SQL 语句组成的一个操作单元,要么所有的操作都成功执行(提交,commit),要么在发生错误时,所有操作都不执行(回滚,rollback)。通过事务,MySQL 能够提供更强的错误恢复能力,并保证数据库在并发访问时的一致性。


事务的四大特性:

事务有四个核心特性,通常被称为 ACID 特性:原子性(Atomicity),一致性(Consistency),持久性(Durability),隔离性(Isolation);

原子性:

在上述操作中,将多个操作打包成一个操作时,此时代表这个操作具有"原子"的,原子就是以前最小的单位,不可拆分。

事务中的操作要么全部成功,要么全部失败。原子性确保了事务是最小的执行单位,无法再分割。即使在事务执行的过程中发生故障,数据库也会通过回滚操作使事务的状态恢复到事务开始之前。


一致性:

在执行事务开始前后,要保证数据是一致的,不会出现对不上的情况。一旦触发"回滚"操作,也要保证回滚回去的数据跟原来一样;

事务执行前后,数据库的状态必须从一个一致的状态转变到另一个一致的状态。所有事务都必须遵循数据库的完整性约束,如主键、外键等,确保数据的完整性和准确性。


持久性:

一旦事务提交,它对数据库的更改是永久性的,即使发生系统崩溃或断电,提交的事务所做的更改也会保留下来。


隔离性:

在并发环境下,多个客户端同时对服务器发起事务请求,一个事务的执行不应受到其他事务的干扰。每个事务应该像是在独占数据库一样执行,直到它提交或回滚。

在并发环境下,可能会产生以下问题:脏读,不可重复读,幻读;


脏读:

脏读指的是一个事务读取了另一个事务尚未提交的数据。这可能会导致读取到不一致的数据,因为另一个事务可能回滚,使得当前事务读取的数据变得无效。

例子:
假设有一场随堂考试,小明(学渣)抄袭小强(学霸)的试卷(这种行为是不好的,只是比喻),此时小强写完了试卷给小明抄,小明写着写着写完了之后,小明就直接提交试卷了。但小强在检查试卷的时候,发现检查试卷的时候很多答案填错了,那么小强肯定将答案改正了回来
,而小明吃了大亏,心里想我*****,还不如自己写...................

核心在于:当小强不仅写完试卷,并且还检查完毕,确保不会修改的情况下,小明再去抄写他的答案,不然都可能出错

解法方法:

当事务B查看事务A(写操作)的数据时候,将事务A的数据进行"加锁",此时事务B不能查看A的数据,必须等待事务A确定下来,才可以查看。
这就相当于降低了 '并发能力',也就降低了数据库服务器的处理效率,提高了 '隔离性' ,也提高了数据的准确性。在并发执行事务过程中,相互之间是互相影响的,彼此的影响越小,隔离性越高;反之影响越大,隔离性越低。


不可重复读

在上述基础上,我们已经把写操作加上锁,这就意味着读操作的事务不能中途查询,以免没有查询到最终结果。

例子:
当我们写博客的时候,此时读者必须等我们发布完成之后,才能阅读我们的博客。

假设我们写完已经发布了 这是事务A

然后读者去查看博客的内容 这是事务B

当我们发布完 我们还觉得内容需要修改一下 可能存在一点问题 又进行发布了 这是事务C

问题出现在事务B此时在读数据的时候,此时我们事务C也执行了,假设博客页面刷新了,事务B发现此时读到的数据跟刚才读到的数据不一样,这就是不可重复读问题;

解法:

在事务B读操作的时候 ,我们也不能执行事务C,必须等事务B执行完之后,才能修改数据,也就是说在"读数据"的时候也不能"写数据";

所以对事务B读操作也加上"锁", 就可以保证事务 B 前后两次读取的数据都是一致的。

脏读和不可重复读的区别:

  • 脏读关注的是一个事务读取另一个事务未提交的数据,且这个数据可能最终会被回滚,因此它是不可靠的。
  • 不可重复读关注的是同一个事务内,在多次读取同一数据时,数据发生了变化(通常是由于其他事务的提交),导致读取结果不一致。

幻读:

幻读是指一个事务在查询数据时,其他事务可能插入、删除或修改记录,导致该事务查询的数据集发生变化,即查询结果出现"幻象"。在一个事务中,查询的结果集在不同的查询操作之间可能不一致。

例子:

刚才约定对读和写操作进行加上锁。

事务A发布第一篇博客

事务B在查询 博客的内容

此时我们并不修改第一篇博客的内容,闲着也是闲着,于是我们继续写了新的一篇博客,第二篇博客。 事务C

在B再一次查询的时候,发现了多出来了一篇博客,此时就是幻读。

解法:

当读者在阅读博客的时候,叫我们啥事别做了,好好休息,简单来说,就是一个事务一个事务来,在执行事务的时候,不要执行任何操作;

实现串行化操作,此时没有并发了,因此效率最低,并且也是隔离性最高的,数据是最准确的。


隔离性的隔离级别:

隔离级别 脏读 不可重复读 幻读 适用场景
读未提交(Read Uncommitted) 高并发、无需完全一致性的数据场景
读已提交(Read Committed) 适用于实时性要求较高的场景
可重复读(Repeatable Read) 适用于大部分应用,默认隔离级别
串行化(Serializable) 保证最大程度的一致性,但性能最低

总结

  • 脏读不可重复读幻读 都是由于并发事务互相干扰所导致的问题。为了避免这些问题,可以选择合适的事务隔离级别:
    • 读未提交:出现脏读,不可重复读,幻读。
    • 读已提交:防止脏读,但可能会出现不可重复读和幻读。
    • 可重复读:防止脏读和不可重复读,但可能会出现幻读。
    • 串行化:完全避免所有并发问题,但性能最差。
相关推荐
YashanDB2 小时前
【YashanDB知识库】XMLAGG方法的兼容
数据库·yashandb·崖山数据库
独行soc2 小时前
#渗透测试#漏洞挖掘#红蓝攻防#护网#sql注入介绍11基于XML的SQL注入(XML-Based SQL Injection)
数据库·安全·web安全·漏洞挖掘·sql注入·hw·xml注入
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云
风间琉璃""3 小时前
bugkctf 渗透测试1超详细版
数据库·web安全·网络安全·渗透测试·内网·安全工具
drebander3 小时前
SQL 实战-巧用 CASE WHEN 实现条件分组与统计
大数据·数据库·sql
IvorySQL3 小时前
IvorySQL 4.0 发布:全面支持 PostgreSQL 17
数据库·postgresql·开源数据库·国产数据库·ivorysql
18号房客3 小时前
高级sql技巧进阶教程
大数据·数据库·数据仓库·sql·mysql·时序数据库·数据库架构
Dawnㅤ3 小时前
使用sql实现将一张表的某些字段数据存到另一种表里
数据库·sql
张声录13 小时前
【ETCD】【实操篇(十二)】分布式系统中的“王者之争”:基于ETCD的Leader选举实战
数据库·etcd
运维&陈同学3 小时前
【模块一】kubernetes容器编排进阶实战之基于velero及minio实现etcd数据备份与恢复
数据库·后端·云原生·容器·kubernetes·etcd·minio·velero