目录
引例
什么是事务
一个完整事务所具有的四大属性
为什么会出现事务
事务常见操作方式
事务隔离级别
为什么要存在隔离级别
一致性
引例
如下图,是一个火车售票系统,当客户端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共同决定!!!