小言_互联网的博客

MySQL事务详解

238人阅读  评论(0)

目录

引例

什么是事务

一个完整事务所具有的四大属性

为什么会出现事务

事务常见操作方式

事务隔离级别

为什么要存在隔离级别

一致性


引例

如下图,是一个火车售票系统,当客户端A发现还有一张票时,将票卖掉,还没执行更新数据库

时,客户端B发现票数大于0,又卖了一次票,A将票数更新回数据库,这样就出现了同一张票卖出

去两次的情况

CURD得满足下面4个特性,才能解决上述问题

买票的过程得是原子的吧
买票互相应该不能影响吧
买完票应该要永久有效吧
买前,和买后都要是确定的状态吧

什么是事务

假设一种场景:你毕业了,学校的教务系统后台 MySQL 中,不再需要你的数据,要删除你的所有
信息(一般不会),那么在删除你的基本信息(姓名,电话,籍贯等)的同时,也删除和你有关的其他
信息,比如:你的各科成绩,你在校表现,甚至你在论坛发过的文章等。这样,就需要多条
MySQL 语句构成,那么所有这些操作合起来,就构成了一个事务
所有的sql操作,一般都会被mysql包装成为事务,以事务的方式提交的!!!

 一个完整事务所具有的四大属性(简称:ACID)

原子性:一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在 间某个环节。事
务在执行过程中发生错误,会被回滚到事务开始前的状态,就像 这个 事务从来 没有执行过一样
一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完
全符合所有 的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工
隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务
并发执行时 由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交 、读提交
可重复读和串行化
持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
为什么会出现事务
为了当应用程序访问数据库的时候,事务能够简化我们的编程模型,不需要我们去考虑各种各
样的潜在错误和并发问题,本质上是为了应用层服务的
MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持,如下图
事务的提交方式常见的有两种:
自动提交
手动提交
自动提交默认是打开的!
也能自己打开或关闭!
事务常见操作方式
为了便于演示,我们将mysql的默认隔离级别设置成读未提交
设置后需要重启终端,进行查看

正常演示 - 证明事务的开始与回滚
启动事务:start transaction / begin
savepoint s:在两条记录间设置断点
rollback to s:回滚到断点s前的上一条数据(s是在两条记录间设置的断点)
rollback:回滚到最开始
非正常演示1 - 证明未commit,客户端崩溃,MySQL自动会回滚
手动启动一个事务的时候,和mysql中是否事务会自动提交无关!如下图
非正常演示2 - 证明commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
非正常演示4 - 证明单条 SQL 与事务的关系
事务没有启动,自动提交打开与不打开的区别如下图

其实我们之前的所有的单挑sql,本质在mysql中,全部各自会被以事务的方式进行提交的!

自动提交是给mysql中的单挑sql设置的,即我们的默认行为

注意:如果一个事务被提交了,则不可以回退!!!

事务隔离级别

一个事务可能由多条SQL构成,也就意味着,任何一个事务,都有执行前,执行中,执行后的阶
数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性 
数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别
隔离级别
读未提交(Read Uncommitted): 在该隔离级别,所有的事务都可以看到其他事务没有提交的
执行结果,相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等
读提交(Read Committed) :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认
的),它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变,会引起不
可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果
可重复读(Repeatable Read): 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多
次读取操作数据时,会看到同样的数据行,会有幻读问题
串行化(Serializable): 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,
从而解决了幻读的问题,在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争
隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见
有,表锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等
查看与设置隔离性
SELECT @@global.tx_isolation(全局) / session.tx_isolation(当前会话) / tx_isolation;
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED |
READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
设置当前会话隔离性,只影响当前会话,不需要重启
设置全局隔离性,另一个会话也会被影响,需要重启
读未提交
如下图,一个事务插入数据未提交,就能被另一个事务读取到,这种现象叫做脏读!如果是误操
作,然后将读取后的结 果交 给上层,就会很不安全!
读提交
如下图,左端事务提交前和提交后,右端事务读取到两种结果,这种现象叫做不可重复读,不可重
复读是一个问题
你已提交,别人能读到,不应该等价于,你已经提交,和你"并行运行"的事务也能读到!!!
不可重复读有什么问题——应用层会有什么影响?以银行为例
如下图,王某在银行的钱余额因为个人原因存在一些变化,从10亿->5500w->3000w,而银行读取
事务这边就会因为不可重复读,即每次读到的值不一样,给王某发了三个礼物,这是存在很大的安
全问题的!!!
可重复读
如下图,左端事务修改完毕提交后,右边事务读取的值还是未发生改变,只有右边事务也commit
后,才能看到更新后的数据!这种现象叫做可重复读!
一般的数据库在可重复读情况的时候,无法屏蔽其他事务insert的数据,因为隔离性实现是对数据
加锁完成的,而insert待插入的数据因为并不存在,那么一般加锁无法屏蔽这类问题,会造成虽然
大部分内容是可重复读的,但是insert的数据在可重复读情况被读取出来,导致多次查找时,会多
查找出来新的记录,就如同产生了幻觉。这种现象,叫做幻读,MySQL解决了这个问题!
串行化
如下图,左端事务更新数据,却卡住了,只能等右端提交后,更新语句才能结束,这说明串行化指
的是事务之间的串行

中隔离级别越严格,安全性越高,但数据库的并发性能也就越低,往往需要在两者之间找一个平衡

点!!!

隔离性:mysql的内部机制,让"同时"启动,并发执行的各个事务,看到不同的数据修改(增删

改),就叫做隔离性!

隔离级别:我们作为一个事务,可以看到不同可见性的数据,程度的不同,叫做隔离级别!

为什么要存在隔离级别

为了安全和效率,安全和效率之间需要找平衡点,这不是mysql决定的,而是由用户决定的,而至

于为什么有种类繁多的隔离级别,这是因为应用场景的需要,比如某些场景下,不需要怎么考虑安

全,只注重效率就行!

一致性

事务执行的结果,必须使数据库从一个一致性状态,变到另一个一致性状态
MySQL中在技术上不存在一致性,技术上,是通过AID(原子性,持久性,隔离性)保证C(一致性)
例如:你给别人转账,你账上的余额减少了,而对方的余额因为系统运行中断却没有增加,这就没
有保证原子性! 你在买票APP上买了一张票,但是当 你去坐车的时候,工作人员告诉你,没有你的
信息,即磁盘上没有保存你的信息,这就可能会给你 带来很 大的损失,这就没有保证持久性!王某
的帐上余额的变化,不可重复读,使得银行多次来人拜访他,打扰了他的生活,就让他很苦恼,这
就没有保证隔 离性!这三例都表明了原子性,持久性,隔离性都是为实现一致性服务的!!!
一致性:由用户和MySQL共同决定!!!

转载:https://blog.csdn.net/weixin_58867976/article/details/128040619
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场