MySQL:事务的理解

MySQL:事务的理解

一、CURD不加控制,会有什么问题 

(1)因为,MySQL里面存的是数据,所以很有可能会被多个客户访问,所以mysqld可能一次会接受到多个关于CURD的请求。(2)且mysql内部是采用多线程来完成数据存储等相关工作的,所以必然会存在对数据并发访问的场景      ——>会导致一些多请求并发可能产生的异常结果

       比如同行转账,按道理是我减100,你加100,但是因为我是同行所以用的是一张数据库的表,可能我减100的时候还没做完网络或者数据库出问题等其他原因导致没有给你加100,那么整个操作就会出现一个中间过程(我减了但是你没有加),这就有问题,在这种情况下我们允许异常产生,一旦操作没有完成我们应该把减掉的100再加回来,就好像什么都没做,等待下次合适的时候再去转账。这就相当于转账之后不要有中间过程,而是在转的时候一旦出现异常就直接进行回滚,因为不回滚的话就会有问题,必须得回滚保证和初始的状态一样,这就叫我们的回滚操作。在高并发的场景下数据或多或少都会出现这样的问题,所以这也就要求mysql必须要有针对这类问题的解决方案。

二、CURD满足什么属性,能解决上述问题?

1. 买票的过程得是原子的吧(要么不抢,要么抢到,出现中间状态会回滚)

2. 买票互相应该不能影响吧(我买的时候你正好过来,我的行为不能影响你,也就是彼此之间得是割裂的)

3. 买完票应该要永久有效吧 ( 购买成功这个情况必须得做持久化 )

4. 买前,和买后都要是确定的状态吧(买前就是没买,买后就是买了,不允许有不确定的状态)

三、什么是事务?

       事务就是一组DML语句组成,这些语句在逻辑上存在相关性(单独一条是没有意义的,比如转账就应该至少有两条sql语句,即我减100,你加100,整体在一起才有转账逻辑,所以事务一定要站在mysql的上层去看待sql语句,具体完成一个由多条sql语句构成的应用层功能,在业务上有具体含义的动作),这一组DML语句要么全部成功,要么全部失败,是一个整体。MySQL提供一种机制,保证我们达到这样的效果。事务还规定不同的客户端看到的数据是不相同的。

    事务就是要做的或所做的事情,主要用于处理操作量大,复杂度高的数据。假设一种场景:你毕业了,学校的教务系统后台 MySQL 中,不再需要你的数据,要删除你的所有信息(一般不会:) ), 那么要删除你的基本信息(姓名,电话,籍 贯等)的同时,也删除和你有关的其他信息,比如:你的各科成绩,你在校表现,甚至你在论坛发过的文章等。这样,就需要多条 MySQL 语句构成,那么所有这些操作合起来,就构成了一个事务。

      正如我们上面所说,一个 MySQL 数据库,可不止你一个事务在运行,同一时刻,甚至有大量的请求被包装成事务, 在向 MySQL 服务器发起事务处理请求。而每条事务至少一条 SQL ,最多很多 SQL ,这样如果大家都访问同样的表数据,在不加保护的情况,就绝对会出现问题。甚至,因为事务由多条 SQL 构成,那么,也会存在执行到一半出错或者 不想再执行的情况,那么已经执行的怎么办呢 ? 

      所以,一个完整的事务,绝对不是简单的sql集合,还需要满足如下四个属性:

1、原子性一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过 一样。

2、一致性在事务开始之前和事务结束以后,数据库的完整性没有被破坏。(一种状态变为另一种状态结果是可预期的)这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

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

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

mysql从技术上只要保证了134,就可以做到2,所以134是因 2是果(还需要上层用户配合) 

上面四个属性,可以简称为 ACID 。

原子性(Atomicity,或称不可分割性)

一致性(Consistency)

隔离性(Isolation,又称独立性)

持久性(Durability)

        mysql需要帮不同的客户端处理不同的事务请求,所以运行期间在自身内部必然存在大量的事务,所以他必须得将事务按照先描述后组织的形式管理起来,所以mysql会把这些事务打包描述成对象,然后放入到事务执行列表里,并帮我们解决一系列执行事务时可能出现的问题

四、为什么会有事务

       事务被 MySQL 编写者设计出来(不是天然就有的,而是使用过程中发现应用层需要才被设计出来的),本质是为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各样的潜在错误和并发问题.(你只需要说你的需求,其他的我帮你处理)可以想一下当我们使用事务时,要么提交,要么回滚,我们不会去考虑网络异常了,服务器宕机了,同时更改一个数据怎么办对吧?因此事务本质上是为了应用层服务的.而不是伴随着数据库系统天生就有的.

备注:我们后面把 MySQL 中的一行信息,称为一行记录

五、事务的版本支持

在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持。

查看数据库引擎 :

mysql> show engines \G         -- 行显示 *************************** 1. row ***************************     Engine: InnoDB    -- 引擎名称     Support: DEFAULT   -- 默认引擎     Comment: Supports transactions, row-level locking, and foreign keys--支持事务、行级锁,外键 Transactions: YES       -- 支持事务         XA: YES Savepoints: YES       -- 支持事务保存点 *************************** 2. row ***************************     Engine: MRG_MYISAM     Support: YES     Comment: Collection of identical MyISAM tables Transactions: NO         XA: NO Savepoints: NO *************************** 3. row ***************************     Engine: MEMORY    --内存引擎     Support: YES     Comment: Hash based, stored in memory, useful for temporary tables Transactions: NO         XA: NO Savepoints: NO *************************** 4. row ***************************     Engine: BLACKHOLE     Support: YES     Comment: /dev/null storage engine (anything you write to it disappears) Transactions: NO         XA: NO Savepoints: NO *************************** 5. row ***************************     Engine: MyISAM         Support: YES     Comment: MyISAM storage engine Transactions: NO           -- MyISAM不支持事务         XA: NO Savepoints: NO *************************** 6. row ***************************     Engine: CSV     Support: YES     Comment: CSV storage engine Transactions: NO         XA: NO Savepoints: NO *************************** 7. row ***************************     Engine: ARCHIVE     Support: YES     Comment: Archive storage engine Transactions: NO         XA: NO Savepoints: NO *************************** 8. row ***************************     Engine: PERFORMANCE_SCHEMA     Support: YES     Comment: Performance Schema Transactions: NO         XA: NO Savepoints: NO *************************** 9. row ***************************     Engine: FEDERATED     Support: NO     Comment: Federated MySQL storage engine Transactions: NULL         XA: NULL Savepoints: NULL 9 rows in set (0.00 sec) 

六、事务的提交方式

事务的提交方式常见的有两种: 自动提交、手动提交

查看事务提交方式 :

show variables like 'autocommit'; 

 

用 SET 来改变 MySQL 的自动提交模式:

SET AUTOCOMMIT=0;            #SET AUTOCOMMIT=0 禁止自动提交 
mysql> SET AUTOCOMMIT=1;           #SET AUTOCOMMIT=1 开启自动提交

七、事务常见操作方式

简单银行用户表

## Centos 7 云服务器,默认开启3306 mysqld服务 netstat -nltp 

## 为了便于演示,我们将mysql的默认隔离级别设置成读未提交

set global transaction isolation level READ UNCOMMITTED; 

## 设置了却没有用 ,因为需要重启终端才可以

select @@tx_isolation;

创建测试表

create table if not exists account(   id int primary key,   name varchar(50) not null default '',   blance decimal(10,2) not null default 0.0 )ENGINE=InnoDB DEFAULT CHARSET=UTF8; 

7.1 正常演示 - 证明事务的开始与(定向)回滚

mysql> show variables like 'autocommit';  -- 查看事务是否自动提交。我们故意设置成自动提交,看看该选项是否影响begin 从这一行往后所有的语句都属于这个事务 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit   | ON   | +---------------+-------+ 1 row in set (0.00 sec) mysql> start transaction;               -- 开始一个事务begin也可以,推荐begin Query OK, 0 rows affected (0.00 sec) mysql> savepoint save1;                -- 创建一个保存点save1(根据需求设置保存点) Query OK, 0 rows affected (0.00 sec) mysql> insert into account values (1, '张三', 100);   -- 插入一条记录 Query OK, 1 row affected (0.05 sec) mysql> savepoint save2;                 -- 创建一个保存点save2 Query OK, 0 rows affected (0.01 sec) mysql> insert into account values (2, '李四', 10000);  -- 在插入一条记录 Query OK, 1 row affected (0.00 sec) mysql> select * from account;             -- 两条记录都在了 +----+--------+----------+ | id | name   | blance   | +----+--------+----------+ |  1 | 张三   |   100.00 | |  2 | 李四   | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> rollback to save2;                 -- 回滚到保存点save2(定向回滚) Query OK, 0 rows affected (0.03 sec) mysql> select * from account;             -- 一条记录没有了 +----+--------+--------+ | id | name   | blance | +----+--------+--------+ |  1 | 张三   | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) mysql> rollback; -- 直接rollback,回滚在最开始,哪怕你一个回滚点都没设置也可以 Query OK, 0 rows affected (0.00 sec) mysql> select * from account;             -- 所有刚刚的记录没有了 Empty set (0.00 sec) commit;--就是把该事务给提交了 无法回滚 

但是一般我们很少手动rollback,事务大多数都是为了非正常情况 

7.2 非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)

-- 终端A mysql> select * from account;          -- 当前表内无数据 Empty set (0.00 sec) mysql> show variables like 'autocommit'; -- 依旧自动提交 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit   | ON   | +---------------+-------+ 1 row in set (0.00 sec) mysql> begin;                            --开启事务 Query OK, 0 rows affected (0.00 sec) mysql> insert into account values (1, '张三', 100);   -- 插入记录 Query OK, 1 row affected (0.00 sec) mysql> select * from account;           --数据已经存在,但没有commit,此时同时查看终端B +----+--------+--------+ | id | name   | blance | +----+--------+--------+ |  1 | 张三   | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) mysql> Aborted                          -- ctrl + \ 异常终止MySQL --终端B mysql> select * from account;           --终端A崩溃前 +----+--------+--------+ | id | name   | blance | +----+--------+--------+ |  1 | 张三   | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) mysql> select * from account;          --数据自动回滚 Empty set (0.00 sec)

 7.3 非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化

--终端 A mysql> show variables like 'autocommit'; -- 依旧自动提交 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec) mysql> select * from account; -- 当前表内无数据 Empty set (0.00 sec) mysql> begin; -- 开启事务 Query OK, 0 rows affected (0.00 sec) mysql> insert into account values (1, '张三', 100); -- 插入记录 Query OK, 1 row affected (0.00 sec) mysql> commit; --提交事务 Query OK, 0 rows affected (0.04 sec) mysql> Aborted -- ctrl + \ 异常终止MySQL --终端 B mysql> select * from account; --数据存在了,所以commit的作用是将数据持久化到MySQL中 +----+--------+--------+ | id | name | blance | +----+--------+--------+ | 1 | 张三 | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) 

7.4 非正常演示3 - 对比试验。证明begin操作会自动更改提交方式,不会受MySQL是否自动提交影响

手动begin就必须手动commit,跟是否是自动提交毫无关系 

-- 终端 A mysql> select *from account; --查看历史数据 +----+--------+--------+ | id | name | blance | +----+--------+--------+ | 1 | 张三 | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) mysql> show variables like 'autocommit'; --查看事务提交方式 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec) mysql> set autocommit=0; --关闭自动提交 Query OK, 0 rows affected (0.00 sec) mysql> show variables like 'autocommit'; --查看关闭之后结果 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | OFF | +---------------+-------+ 1 row in set (0.00 sec) mysql> begin; --开启事务 Query OK, 0 rows affected (0.00 sec) mysql> insert into account values (2, '李四', 10000); --插入记录 Query OK, 1 row affected (0.00 sec) mysql> select *from account; --查看插入记录,同时查看终端B +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> Aborted --再次异常终止 -- 终端B mysql> select * from account; --终端A崩溃前 +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> select * from account; --终端A崩溃后,自动回滚 +----+--------+--------+ | id | name | blance | +----+--------+--------+ | 1 | 张三 | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec)

7.5 非正常演示4 - 证明单条 SQL 与事务的关系

--实验一 -- 终端A mysql> select * from account; +----+--------+--------+ | id | name | blance | +----+--------+--------+ | 1 | 张三 | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) mysql> show variables like 'autocommit'; +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec) mysql> set autocommit=0; --关闭自动提交 Query OK, 0 rows affected (0.00 sec) mysql> insert into account values (2, '李四', 10000); --插入记录 Query OK, 1 row affected (0.00 sec) mysql> select *from account; --查看结果,已经插入。此时可以在查看终端B +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> ^DBye --ctrl + \ or ctrl + d,终止终端 --终端B mysql> select * from account; --终端A崩溃前 +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> select * from account; --终端A崩溃后 +----+--------+--------+ | id | name | blance | +----+--------+--------+ | 1 | 张三 | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) -- 实验二 --终端A mysql> show variables like 'autocommit'; --开启默认提交 +---------------+-------+ | Variable_name | Value | +---------------+-------+ | autocommit | ON | +---------------+-------+ 1 row in set (0.00 sec) mysql> select * from account; +----+--------+--------+ | id | name | blance | +----+--------+--------+ | 1 | 张三 | 100.00 | +----+--------+--------+ 1 row in set (0.00 sec) mysql> insert into account values (2, '李四', 10000); Query OK, 1 row affected (0.01 sec) mysql> select *from account; --数据已经插入 +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> Aborted --异常终止 --终端B mysql> select * from account; --终端A崩溃前 +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) mysql> select * from account; --终端A崩溃后,并不影响,已经持久化。autocommit起作用 +----+--------+----------+ | id | name | blance | +----+--------+----------+ | 1 | 张三 | 100.00 | | 2 | 李四 | 10000.00 | +----+--------+----------+ 2 rows in set (0.00 sec) 

7.6 结论

1、只要输入begin或者start transaction,事务便必须要通过commit提交,才会持久化,与是否设置set autocommit无关。

2、事务可以手动回滚,同时,当操作异常,MySQL会自动回滚

3、对于 InnoDB 每一条 SQL 语言都默认封装成事务,自动提交。(select有特殊情况,因为 MySQL 有MVCC )

从上面的例子,我们能看到事务本身的原子性(回滚),持久性(commit)

7.7 事务操作注意事项  

1、如果没有设置保存点,也可以回滚,只能回滚到事务的开始。直接使用 rollback(前提是事务还没有提交)

2、如果一个事务被提交了(commit),则不可以回退(rollback)

3、可以选择回退到哪个保存点

savepoint save1; 设置保存点     rollback to save2;回退保存点

4、InnoDB 支持事务, MyISAM 不支持事务

5、开始事务可以使 start transaction 或者 begin

 

0

Read more

Flutter 组件 http_requests 适配鸿蒙 HarmonyOS 实战:极简网络请求,构建边缘端轻量级 RESTful 通讯架构

Flutter 组件 http_requests 适配鸿蒙 HarmonyOS 实战:极简网络请求,构建边缘端轻量级 RESTful 通讯架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 http_requests 适配鸿蒙 HarmonyOS 实战:极简网络请求,构建边缘端轻量级 RESTful 通讯架构 前言 在鸿蒙(OpenHarmony)生态迈向多端协同、涉及大量轻量级 IOT 设备(如智能穿戴、工业传感器)及微服务透传的背景下,如何实现快速、低开销的 HTTP 通讯,已成为决定应用“响应敏捷度”的关键工程要素。在鸿蒙设备这类强调内存精简与极速启动的环境下,如果应用依然无差别地引入像 Dio 这种包含复杂拦截器、适配器及多重缓存逻辑的“重型网络航母”,由于由于框架初始化开销大、内存足迹(Memory Footprint)偏深,极易由于由于“过度封装”导致边缘设备主线程的瞬间负载过高。 我们需要一种能够剥离样板代码、支持一键 JSON

By Ne0inhk
【终极对决】Kafka vs RabbitMQ:深入剖析消息中间件双雄,附选型指南与代码实战

【终极对决】Kafka vs RabbitMQ:深入剖析消息中间件双雄,附选型指南与代码实战

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[[email protected]] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? * 专栏导航: 码农阿豪系列专栏导航 面试专栏:收集了java相关高频面试题,面试实战总结🍻🎉🖥️ Spring5系列专栏:整理了Spring5重要知识点与实战演练,有案例可直接使用🚀🔧💻 Redis专栏:Redis从零到一学习分享,经验总结,案例实战💐📝💡 全栈系列专栏:海纳百川有容乃大,可能你想要的东西里面都有🤸🌱🚀 目录 * 【终极对决】Kafka vs RabbitMQ:深入剖析消息中间件双雄,附选型指南与代码实战 * 一、核心概念与架构模型图解:两种不同的设计哲学 * RabbitMQ:精密的“路由引擎” * Kafka:

By Ne0inhk
Flutter 组件 activity_files 适配鸿蒙 HarmonyOS 实战:文件活动流治理,构建高性能存储沙箱访问与资产全生命周期管理架构

Flutter 组件 activity_files 适配鸿蒙 HarmonyOS 实战:文件活动流治理,构建高性能存储沙箱访问与资产全生命周期管理架构

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.ZEEKLOG.net Flutter 组件 activity_files 适配鸿蒙 HarmonyOS 实战:文件活动流治理,构建高性能存储沙箱访问与资产全生命周期管理架构 前言 在鸿蒙(OpenHarmony)生态迈向全场景分布式协同、涉及海量多媒体资产处理及严苛应用沙箱(Sandbox)隔离的背景下,如何实现一套既能穿透复杂的层级目录、又能实时追踪文件变更活动且具备极高 I/O 吞吐能力的存储治理架构,已成为决定应用性能广度与数据安全深度。在鸿蒙设备这类强调 AOT 极致性能与受限文件权限周期的环境下,如果应用依然采用陈旧的同步文件读取或缺乏活动追踪的直接 I/O,由于由于频繁的磁盘竞争,极易由于由于“主线程阻塞”或“资产状态不同步”导致用户在管理大型媒体库时发生明显的感知性卡顿。 我们需要一种能够解耦文件路径、支持异步流式追踪(Activity Tracking)且符合鸿蒙分布式文件系统安全范式的操作框架。 activity_files 为 Flutter 开发者引入了“

By Ne0inhk
Flume架构深度解析:构建高可用大数据采集系统

Flume架构深度解析:构建高可用大数据采集系统

Flume架构深度解析:构建高可用大数据采集系统 🌟 你好,我是 励志成为糕手 ! 🌌 在代码的宇宙中,我是那个追逐优雅与性能的星际旅人。 ✨ 每一行代码都是我种下的星光,在逻辑的土壤里生长成璀璨的银河; 🛠️ 每一个算法都是我绘制的星图,指引着数据流动的最短路径; 🔍 每一次调试都是星际对话,用耐心和智慧解开宇宙的谜题。 🚀 准备好开始我们的星际编码之旅了吗? 目录 * Flume架构深度解析:构建高可用大数据采集系统 * 摘要 * 1. Flume架构概览 * 1.1 整体架构设计理念 * 1.2 Agent生命周期管理 * 2. 核心组件深度解析 * 2.1 Source组件详解 * 2.1.1 Exec Source实现机制 * 2.1.2 Avro Source网络通信 * 2.2 Channel组件深度分析 * 2.2.1 Memory Channel内存优化策略 * 2.

By Ne0inhk