MySQL 事务

  1. 事务的背景

(1)事务是指逻辑上的一组操作,组成在这组操作的各个单元要么全部成功, 要么全部失败。

事务中的典型事例: 转账
例:
A 的账户有 5000 块钱
B 的账户有 1000 块钱
当 A 转钱给 B 时,分成两个步骤来操作
a. A 的账户 - 钱
b. B 的账户 + 钱
此时当执行完 a 操作的时候,可能出现极端情况,导致 b 操作没有正确执行,这是一组操作。
事务的存在就是为了解决类似于转账这样的问题的。

(2)事务的作用:保证在一个事务中多次操作数据库表中的数据时,要么全部成功,要么全部失败。

  1. 事务的基本特性

(1) 原子性:一个事务是一个不可分割的工作单位,其中包含的操作,要么全部都执行成功,要么都执行失败。
如果在执行过程中,第一步成功了,第二步出现了问题,为了避免数据错误,往往都会进行回滚操作(rollback).

(2) 一致性: 事务执行前后, 数据要处在一种合法的情况.
无论事务最后执行的成功或者失败, 最终数据库的数据都是满足实际生活的事物逻辑的.
例如上述的转账操作:
其中隐含的条件即合法条件是:
a. 转账之前和转账之后, 都必须保证 A 和 B 的金额相加始终等于 6000;
b. 金额不能为负数.

(3) 持久性: 一个事务一旦被成功提交, 对于数据库的修改就应该是永久的, 接下来的其他操作或者故障都不会对刚才已经完成的事物造成影响.

(4) 隔离性: 多个事务并发执行时, 事务的内部操作和其他事务的内部操作是相互隔离, 互不影响的.

这里解释一下并发, 并行以及他们的关系: 假如这台计算机现在有扣扣, 微信, CSDN, IDEA 等多个程序在同时运行.
但是对于一个 CPU 来说, 同一时刻只能执行一个程序的代码(只能运行一个程序), 此时, CPU 会先执行程序1(执行一小会),然后保存此时执行的程序1, 切换到程序2, 执行一小会后保存接着执行程序3, 执行一小会后再执行程序1…
从微观上来看, CPU 上的程序其实都是串行执行的, 即一个接一个的执行, 但是由于 CPU 的切换速度极快, 所以从宏观上来看, 感觉这多个程序好像是"同时"执行的, 这就是并发.
但是当你有好几个 CPU 在执行这些程序, 从微观上看, CPU1 执行程序1, CPU2 执行程序2…, 这些程序也是"同时"执行的, 这就是并行.
在实际编程中, 一般不严格区分并行和并发的区别, 都用并发来描述.

这里再次举转账的例子来说明一下并发: A 给 B 转账 1000, 并发执行两次 当第一次转账的时候, 计算 5000 - 1000,在这个操作还没有执行完生效之前, 并发的执行了第二个事务, 第二个事务此时也需要读取 A 的余额, 此时还是 5000, 这就会出现错误的情况.
为啥会出现这种情况: 本质的原因是多个任务在并发式执行的时候, 执行第一个任务时,到底执行了第一个任务的多少代码然后转换到第二个任务, 这是未知的, 执行第二个任务时, 执行了多少代码后转换到第一个任务也是未知的, 这都由操作系统底层的调度器来实现的.

综上, 并发可能会影响数据的准确性, 但是, 因为并发可以提高程序的执行效率, 所以在不影响数据正确性的情况下,
我们还是希望能够尽可能的让多个事务(操作)并发执行.

事务的隔离性就是描述并发过程中对应的一些问题.

  1. 并发操作数据库的时候可能带来的问题

(1) 脏读: 指一个事务读取了另一个事务未提交的数据

下面举例说明一下脏读:
我正在写一个类 Class, 添加了一个属性 String name, 有人偷看了一眼我的屏幕, 知道了我的 Class 类中有一个 String name, 然后他就走了, 但是我在提交代码之前, 又把这个 name 属性给删除了, 这个人就产生了"脏读", 读到了脏数据(错误的数据).
在这里插入图片描述
此时我们对隔离性没有做任何要求, 于是就产生了脏读.

为了避免脏读, 可以给写操作加锁, 在提交之前就不能被读取(提交了隔离性, 但是降低了并发性).

(2) 不可重复读: 一个事务内先后读到的两次数据不一致.

举个栗子说明一下什么是不可重复读;
我写了一个带 name 属性的 Class 类, 然后提交了, 这个偷看的人正在看我的代码, 这个时候, 我又把 name 给删了, 再次提交, 这个偷看的人发现我的代码不一样了.
在这里插入图片描述

不可重复读和脏读的区别是: 不可重复读是读取已经提交的数据.

为了避免不可重复读, 可以给读操作"加锁",在没读完之前不能修改(提高了隔离性, 降低了并发性)
在这里插入图片描述
(3) 幻读(虚读): 同一个事务中, 多次查询返回的结果集不一样
事务A首先根据条件索引得到N条数据,然后事务B改变了这N条数据之外的M条或者增添了M条符合事务A搜索条件的数据,导致事务A再次搜索发现有N+M条数据了,就产生了幻读。

举个栗子说明一下什么是幻读:
刚才在处理不可重复读的时候, 是给读加锁, 此时我不能在偷看的人读 Student 的时候修改 Student 类, 但是我可以修改别的类, 例如改 Class_id 这个类或者新增一个类, 当我下次提交代码的时候, 偷看的人就会发现又不一样了!!!

如果要避免幻读出现还得进一步提高隔离性.即"串行化".
偷看的人在读代码的时候我不能有任何操作, 我在写代码的时候不进行任何操作, 什么都不能看, 等我写完才能看, 不能同时进行任何操作.

  1. MySQL 中的事务隔离级别

(1) Read Uncommitted(未提交读): 允许读取未提交数据, 并行最大, 隔离性最小, 会产生 “脏读” “不可重复读” “幻读”.

(2) Read Committed(提交读): 只允许读提交的数据, 相当于"写加锁", 保证一个事务不会读到另一个事务已修改但未提交的数据, 能够避免 “脏读”, 但是不能避免 “不可重复读” 和 “幻读”.

(3) Repeatable Read(重复读): 保证一个事务不会修改已经由另一个事务读取的数据, 相当于"读加锁" 和 “写加锁”, 避免了"脏读" 和"不可重复读", 但是不能避免"幻读"(MySQL 的默认事务隔离级别).

(4) Serializable(串行化): 事务严格串行执行, 隔离性最高, 并行程度最低,资源消耗最大, 可以解决"幻读".

  1. MySQL 事务操作

(1) 开启事务(禁止了自动提交)

start transaction;

(2) 提交事务(手动)

commit;

(3) 回滚事务

rollback;

下面举个栗子实际操作一下, 还是 A 转账给 B 1000

准备数据:
在这里插入图片描述
在这里插入图片描述
演示提交事务在这里插入图片描述
演示回滚事务
在这里插入图片描述
事务提交之后, SQL 语句对数据库的操作才会永久保存, 在提交之前进行回滚操作, 就会撤销之前执行的 SQL 语句, 回到事务刚开始的状态, 提交之后就不能回滚事务了.
提交事务和回滚事务都是代表结束当前事务.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值