事务(Transaction)是数据库学习中非常重要的一种概念,作为关系型数据库的核心组成,在数据安全方面有着非常重要的作用。
事务在各大数据库中都有非常广泛的应用,并且对于很多业务,例如电商、支付,是保证其可以正常运行的根基。
本文会逐步解析数据库事务的核心特性,以获得对事务更深的理解,主要以MySql的InnoDB引擎来讲解。
希望对各位有所帮助,觉得不错可以给点个赞哦~
事务是一个数据库操作序列,由事务开始与事务结束之间执行的全部数据库操作组成,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。
白话讲就是,要么做完,要么别做,做一半了别想跑,你得给把烂摊子收好再走人!
什么是ACID,即:原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)、持久性(Durability)
来看一个银行转账的案例简单体会一下,然后我们再来详细解释
小明用网银给小红转账100元,在这种交易的过程中,有几个问题需要思考
一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。
事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
事务的一致性指的是在一个事务执行之前和执行之后数据库都必须处于一致性状态。
如果事务成功地完成,那么系统中所有变化将正确地应用,系统处于有效状态。
如果在事务中出现错误,那么系统中的所有变化将自动地回滚,系统返回到原始状态。
一致性依赖于原子性和隔离性。
指的是在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间。
由并发事务所做的修改必须与任何其他并发事务所做的修改隔离。
事务查看数据更新时,数据所处的状态要么是另一事务修改它之前的状态,要么是另一事务修改它之后的状态,事务不会查看到中间状态的数据。
指的是只要事务成功结束,它对数据库所做的更新就必须永久保存下来。
即使发生系统崩溃,重新启动数据库系统后,数据库还能恢复到事务成功结束时的状态。
ACID根本问题,是针对不同的事务同时对同一份数据进行写操作的。
InnoDB是MySql中唯一支持事务的存储引擎,那么它是如何实现ACID的呢?
主要通过两门技术:并发控制技术和日志恢复技术
并发控制技术保证了事务的隔离性,使数据库的一致性不会因为并发执行的操作被破坏。
日志恢复技术保证了事务的原子性,使一致性、持久性不会因事务或系统故障被破坏。
主要就是上锁,流程如下:
Redo Log:
Redo Log记录的是新数据的备份。在事务提交前,只要将Redo Log持久化即可,不需要将数据持久化。当系统崩溃时,虽然数据没有持久化,但是Redo Log已经持久化。系统可以根据Redo Log的内容,将所有数据恢复到最新的状态。
Undo Log:
Undo Log是旧数据的备份,在操作任何数据之前,首先将数据备份到Undo Log,然后进行数据的修改。如果出现了错误或者用户执行了回滚语句,系统可以利用Undo Log中的备份将数据恢复到事务开始之前的状态。
前面提到了,数据库的隔离性是依靠并发控制来实现的,也就是通过加锁来实现的。
数据库是个高并发的应用,同一时间会有大量的并发访问,如果加锁过度,会极大的降低并发处理能力。
所以对于加锁的处理,就成了数据库的重中之重。
一次封锁法,就是在方法的开始阶段,已经预先知道会用到哪些数据,然后全部锁住,在方法运行之后,再全部解锁。
这种方式是最为熟知和常用的方法,可以有效的避免循环死锁。
一次封锁法在数据库中并不好用,因为在事务开始阶段,数据库并不知道会用到哪些数据。
数据库采用的是两段锁,将事务分成两个阶段:
事务 | 加锁/解锁处理 |
---|---|
begin; | |
insert into test ….. | 加insert对应的锁 |
update test set… | 加update对应的锁 |
delete from test …. | 加delete对应的锁 |
commit; | 事务提交时,同时释放insert、update、delete对应的锁 |
两段锁无法避免死锁,但是两段锁协议可以保证事务的并发调度是串行化,关于穿行化后面会进行解释。
隐式事务,即单条语句。
了解隔离级别之前,我们需要先了解三个概念,脏读、幻读、不可重复读。
所谓脏读是指一个事务中访问到了另外一个事务未提交的数据,如图:
一个事务读取同一条记录2次,得到的结果不一致,如图:
一个事务读取2次,得到的记录条数不一致,如图:
在数据库操作中,为了有效保证并发读取数据的正确性,提出的事务隔离级别。
我们的数据库锁,也是为了构建这些隔离级别存在的。
隔离级别 | 脏读(Dirty Read) | 不可重复读(NonRepeatable Read) | 幻读(Phantom Read) |
---|---|---|---|
未提交读(Read uncommitted) | ✅ | ✅ | ✅ |
已提交读(Read committed) | ❌ | ✅ | ✅ |
可重复读(Repeatable read) | ❌ | ❌ | ✅ |
可串行化(Serializable ) | ❌ | ❌ | ❌ |
可重复读是InnoDB默认级别
事务的 ACID 四大基本特性在很大程度上保证了数据库的安全运行。
虽然ACID有很多好处,但是也有一些缺点,尤其是隔离性会对性能有比较大影响,所以在实际的使用中我们也会根据业务的需求对隔离性进行调整。