- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章MySQL事务控制流与ACID特性由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
事务处理是一种对必须整批执行的 mysql 操作的管理机制,在事务过程中,除非整批操作全部正确执行,否则中间的任何一个操作出错,都会回滚 (rollback) 到最初的安全状态以确保不会对系统数据造成错误的改动.
mysql 5.5 之后,默认的存储引擎从 mylsam 替换成了 innodb,这其中的一个重要原因就是因为 innodb 支持事务,我们用 show engines 来看一下 mysql 中对各种存储引擎的描述.
事务最重要的四个特性通常被称为 acid 特性: a - atomicity 原子性: 一个事务是一个不可分割的最小单位,事务中的所有操作要么全部成功,要么全部失败,没有中间状态。原子性主要是通过事务日志中的回滚日志(undo log)来实现的,当事务对数据库进行修改时,innodb 会根据操作生成相反操作的 undo log,比如说对 insert 操作,会生成 delete 记录,如果事务执行失败或者调用了 rollback,就会根据 undo log 的内容恢复到执行之前的状态.
c - consistency 一致性: 事务执行之前和执行之后数据都是合法的一致性状态,即使发生了异常,也不会因为异常引而破坏数据库的完整性约束,比如唯一性约束等.
i - isolation 隔离性: 每个事务是彼此独立的,不会受到其他事务的执行影响,事务在提交之前对其他事务不可见。隔离性通过事务的隔离级别来定义,并用锁机制来保证写操作的隔离性,用 mvcc 来保证读操作的隔离性,将在下文详细介绍.
d - durability 持久性: 事务提交之后对数据的修改是持久性的,即使数据库宕机也不会丢失,通过事务日志中的重做日志(redo log)来保证。事务修改之前,会先把变更信息预写到 redo log 中,如果数据库宕机,恢复后会读取 redo log 中的记录来恢复数据.
mysql 事务控制有几个重要节点,分别是事务的开启,提交,回滚和保存点.
开启事务代表事务开始执行,语句为 start transaction 或者 begin,提交事务代表将事务中的所有更新都写到磁盘的物理数据库,事务正常执行结束,语句为 commit,如果发生异常需要回滚,语句为 rollback。要注意的是,一旦事务已经提交,就不能回滚了,因此,在代码执行过程中捕获到异常的时候需要直接执行 rollback 而不是 commit.
比如 a 向 b 转账 100 元的事务:
1
2
3
4
5
6
7
8
9
10
11
|
// 正常执行,提交
begin
; # 开启事务
update
account_balance
set
balance = balance - 100.00
where
account_name =
'a'
;
update
account_balance
set
balance = balance + 100.00
where
account_name =
'b'
;
commit
; # 提交事务
// 发生异常,回滚
begin
; # 开启事务
update
account_balance
set
balance = balance - 100.00
where
account_name =
'a'
;
update
account_balance
set
balance = balance + 100.00
where
account_name =
'b'
;
rollback
; # 事务回滚
|
在复杂场景中,有时我们不需要全盘回滚整个操作,而是分批执行,回滚到某个节点就好了,相当于是在一个大事务下嵌套了若干个子事务,在 mysql 中可以使用保留点 savepoint 来实现.
1
2
3
4
5
6
7
8
9
10
11
12
|
begin
;
insert
into
user_tbl (id)
values
(1) ;
insert
into
user_tbl (id)
values
(2) ;
rollback
; # 1,2 都没有写入
begin
;
insert
into
user_tbl (id)
values
(1) ;
savepoint s1;
insert
into
user_tbl (id)
values
(2) ;
rollback
to
s1; # 回滚到保留点 s1, 因此 1 成功写入,2 被回滚, 最终结果为 1
release savepoint s1; # 释放保留点
|
顺便提一下,事务有隐式事务(自动提交)和显示事务(必须手动提交)两种,mysql 默认为隐式事务,会进行自动提交,通过 autocommit 参数来控制.
1
2
3
4
5
6
7
8
9
10
11
|
# 查看变量
show variables
like
'autocommit'
;
+
---------------+-------+
| variable_name | value |
+
---------------+-------+
| autocommit |
on
|
+
---------------+-------+
# 开启自动提交(默认)
set
autocommit = 1;
# 关闭自动提交
set
autocommit = 0;
|
在自动提交状态下,如果没有显示的开启事务,那每一条 dml 语句都是一个事务,系统会自动对每一条 sql 执行 commit 操作。使用 begin 或 start transaction 开启一个事务之后,自动提交将保持禁用状态,直到使用 commit 或 rollback 结束事务之后,自动提交模式会恢复到之前的状态.
关于事务还有另一个参数 completion_type,默认取值为 0 (no_chain) 。
1
2
3
4
5
6
7
|
# 查看变量
show variables
like
'completion_type'
;
+
-----------------+----------+
| variable_name | value |
+
-----------------+----------+
| completion_type | no_chain |
+
-----------------+----------+
|
completion_type = 0: 默认值,执行 commit 后不会自动开启新的事务。 completion_type = 1: 执行 commit 时,相当于执行 commit and chain,自动开启一个相同隔离级别的事务。 completion_type = 2: 执行 commit 时,相当于执行 commit and release,提交事务后自动断开服务器连接.
在实际产线环境下,可能会存在大规模并发请求的情况,如果没有妥善的设置事务的隔离级别,就可能导致一些异常情况的出现,最常见的几种异常为脏读(dirty read)、幻读(phantom read)和不可重复读(unrepeatable read).
脏读指一个事务访问到了另一个事务未提交的数据,如下过程
不可重复读指一个事务多次读取同一数据的过程中,数据值 内容 发生了改变,导致没有办法读到相同的值,描述的是针对同一条数据 update/delete 的现象,如下过程:
幻读指一个事务多次读取同一数据的过程中,数据 条数 发生了改变,仿佛产生了幻觉,描述的是针对全表 insert/delete 的现象,如下过程:
串行化的事务处理方式当然是最安全的,但是串行无法满足数据库高并发访问的需求,作为妥协,有时不得不降低数据库的隔离标准来换取事务的并发能力,通过在可控的范围内牺牲正确性来换取效率的提升,这种权衡通过事务的隔离级别来实现.
数据库有 4 种事务隔离级别,由低到高依次为 读未提交 read uncommitted 、读已提交 read committed 、可重复读 repeatable read 、串行化 serializable .
(1)读未提交 read uncommitted 允许读取未提交的内容,这种级别下的查询不会加锁,因此脏读、不可重复读、幻读都有可能发生。 (2)读已提交 read committed 只允许读取已提交的内容,这种级别下的查询不会发生脏读,因为脏数据属于未提交的数据,所以不会被读取,但是依然有可能发生不可重复读和幻读。 (3)可重复读 repeatable read (mysql 的默认隔离级别) 使用行级锁来保证一个事务在相同查询条件下两次查询得到的数据结果一致,可以避免脏读和不可重复读,但是没有办法避免幻读。 (4)串行化 serializable 使用表级锁来保证所有事务的串行化,可以防止所有的异常情况,但是牺牲了系统的并发性.
四种隔离级别中上述三种异常情况的容忍度如下(代表允许,代表禁止):
查看隔离级别的命令为
1
2
3
|
show variables
like
'transaction_isolation'
;
# 或者
select
@@
global
.tx_isolation, @@tx_isolation;
|
第二种方式可以查看全局和当前会话的隔离级别.
设置隔离级别的命令为
1
2
3
4
|
# 将当前会话的隔离级别设为读未提交
set
session
transaction
isolation
level
read
uncommitted
;
# 将全局的隔离级别设为读未提交
set
global
transaction
isolation
level
read
uncommitted
;
|
到此这篇关于mysql 事务详解的文章就介绍到这了,更多相关mysql内容请搜索我以前的文章或继续浏览下面的相关文章希望大家以后多多支持我! 。
原文链接:https://blog.csdn.net/wallace_www/article/details/118768540 。
最后此篇关于MySQL事务控制流与ACID特性的文章就讲到这里了,如果你想了解更多关于MySQL事务控制流与ACID特性的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
大家好,我完成了这个基本的 C 程序,它向输入任何给定数字集的用户显示有序集、最小值、最大值、平均值和中值。我遇到的问题是,当我打印数字时,我必须使用诸如“3.2%f”之类的东西来设置标准的精度,我怎
我有这个基于 Python 的服务守护进程,它正在执行大量多路复用 IO(选择)。 从另一个脚本(也是 Python)我想查询这个服务守护进程的状态/信息和/或控制处理(例如暂停它、关闭它、更改一些参
我读到 Fortran 对表达式求值的顺序有严格的规则。对于某些数值算法来说,这一点非常重要。 数值 C 程序如何控制浮点运算的顺序并防止编译器“优化”到不需要的运算顺序,例如将 (a*b)*c 更改
上下文: 整个问题可以概括为我正在尝试复制调用system(或fork)的行为,但在 mpi 环境中。 (事实证明,你不能并行调用system。)这意味着我有一个程序在许多节点上运行,每个节点上有一个
我考虑过控制scanf来接受c中的任何输入。我的概念是等待10秒(或任何其他时间)来接受任何输入。10秒后它将退出并且不再接收任何输入。 int main(){ int a,b,c,d; sca
我正在尝试使用生成器停止 setTimeOut 上的执行流程。我究竟做错了什么?我无法让 console.log 每 1500 毫秒退出一次。我是 node 的新手,如果我在做一件非常愚蠢的事情,请不
我希望我的应用程序的 Activity 堆栈包含同一 Activity 的多个实例,每个实例处理不同的数据。因此,我将让 Activity A 在我的 Activity 堆栈中处理数据 a、b、c 和
我有这个 bash 文件,它向设备询问 OpenSSH 的 IP、密码等。 现在,如果我使用 ssh root@ip,我必须输入密码。这真的很烦人。第二;我不能让我的脚本向它发送命令。 这就是我想要的
我正在尝试测试我有权访问的机器的缓存属性。为此,我正在尝试读取内存并对其计时。我改变工作集大小和步幅访问模式以获得不同的测量值。 代码如下所示: clock1 = get_ticks() for (i
我正在尝试编写一个 makefile 来替换用于构建相当大的应用程序的脚本之一。 当前脚本一次编译一个文件,使用 make 的主要原因是并行化构建过程。使用 make -j 16 我目前在办公室服务器
我正在制作一个小的测试程序,它演示了一个粗糙的控制台界面。 该程序是一个低于标准的典型获取行、响应程序,它甚至不识别“退出”,并希望您通过按 control-c 强制退出。在 Mingw32 上完成。
好的,我有一个 VOIP 电话。我知道电话的 IP 地址和端口,并且可以完全访问电话,我正在使用它通过 SIP 中继调用 SIP 电话。 我基本上想随时查看手机上发生的事情,但我不知道从哪里开始。 如
是否可以指定 CWinApp::WriteProfileString() 使用的应用程序名称? 如果我使用 CWinApp::SetRegistryKey 将我的公司名称设置为“MyCompany”,
我正在尝试用 Python 控制 Tor。我在 stackoverflow 上阅读了其他几个关于这个主题的问题,但没有一个能回答这个问题。 我正在寻找一种方法,以便在命令运行时为您提供“新身份”、新
最近在做一个项目,涉及到iPhone设备和手表传输数据、控制彼此界面跳转,在网上找了很多资料,发现国内的网站这方面介绍的不多,而国外的网站写的也不是很全,所以在这写这篇文章,给大家参考一下,望大神指
我想增加图中值的范围。在示例中,值的范围从 50 到 200。但是,我需要按如下方式分配值:50 75 100 125 150 175 200 并且最好使用 scale_fill_gradientn
我有一个IconButton,当按下时波纹效果是圆形的并且比按钮的面积大,我怎样才能减少点击按钮时波纹效果的大小? IconButton( constraints
我正在使用代码契约(Contract)为我的项目生成附属程序集。基本上它为项目的 MyAssembly.dll 创建一个 MyAssembly.Contracts.dll。这应该放在你的程序集旁边,但
我想使用分面绘制图形,其中面板之间的边缘不同。面板按字母顺序自动排序(按照 ggplot 中的惯例)。一个简单的例子: library(igraph) library(ggraph) g <- mak
我想为我的 Android 应用程序创建一个小部件,以显示有关位置的一些实时详细信息,例如天气。但我想在任何时候允许最多 3 个小部件实例,每个实例都有不同的位置。我不确定该怎么做,也找不到任何信息。
我是一名优秀的程序员,十分优秀!