事务是什么?
事务可以看成就是要做的事情,这个事情可能要很很多步骤去完成。
在我们计算机语言中,事务一般指的是数据库事务,指的是对数据库中表数据的一系列操作,可以是一条sql,也可以是多条sql。但是这些sql操作在一个事务中,要么都执行成功,要么都执行失败。也就是说事务,需要遵循四大特性:ACID,这个应该都很熟悉
ACID四大特性
A:原子性,事务是一个不可分割的工作单元,一个事务中的sql操作要么都执行成功,要么都执行失败
C:一致性;数据库从一种状态转化为另外一种一致性状态。事务开始之前和结束后,数据库的完整约束性没有被破坏
i:隔离性,事务与事务之间是互不干扰
D:持久性,事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响
事务类型
根据事务类型的不同呢:可以分为这个扁平事务、带有保存点的扁平事务、链事务、嵌套事务嵌套事务、分布式事务,平时默认用的是这个扁平事务(开启,提交/回滚),有兴趣可另外查阅资料了解
如何保证ACID特性
1.原子性:
实现原子性的关键呢,就是当事务回滚时能够撤销所有成功执行的sql语句。Innodb主要是靠这个undolog,当事务对数据库进行修改的时候呢,InnoDB会生成对应的undolog。如果事务执行失败或调用rollback,导致事务回滚,便可以利用undo log中的信息将数据进行回滚,undo log逻辑日志,记录sql相关执行的信息。需要回滚时,会根据undolog 的内容做与之相反的工作。对于insert,回滚时会执行delete。对于delete,回滚时会执行insert。对于update,回滚时,执行相反的update。
2.持久性实现原理
主要借助这个redo log日志。InnoDB执行引擎呢提供了缓存,来减少磁盘IO,提高我们每次读写数据的效率。当数据读取数据时。当从数据库读取数据时,会首先从Buffer Pool中读取,如果Buffer Pool中没有,则从磁盘读取后放入Buffer Pool。当向数据库写入数据时,会首先写入Buffer Pool,Buffer Pool中修改的数据会定期刷新到磁盘中(这一过程称为刷脏);如果MySQL宕机,而此时Buffer Pool中修改的数据还没有刷新到磁盘,就会导致数据的丢失,事务的持久性无法保证。于是,redo log被引入来解决这个问题。当数据修改时,除了修改Buffer Pool中的数据,还会在redo log记录这次操作。当事务提交时,会调用fsync接口对redo log进行刷盘。如果MySQL宕机,重启时可以读取redo log中的数据,对数据库进行恢复。redo log采用的是WAL(Write-ahead logging,预写式日志),所有修改先写入日志,再更新到Buffer Pool,保证了数据不会因MySQL宕机而丢失,从而满足了持久性要求。
既然redo log也需要在事务提交时将日志写入磁盘,为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:
-
刷脏是随机IO,因为每次修改的数据位置随机,但写redo log是追加操作,属于顺序IO。
-
刷脏是以数据页(Page)为单位的,MySQL默认页大小是16KB,一个Page上一个小修改都要整页写入。而redo log中只包含真正需要写入的部分,无效IO大大减少。
3.隔离性实现原理 隔离性追求的是并发情形下事务之间互不干扰隔离性追求的是并发情形下事务之间互不干扰。简单起见,我们主要考虑最简单的读操作和写操作(加锁读等特殊读操作会特殊说明),那么隔离性的探讨,主要可以分为两个方面。 第一方面,(一个事务)写操作对(另一个事务)写操作的影响:锁机制保证隔离性。 第二方面,(一个事务)写操作对(另一个事务)读操作的影响:MVCC保证隔离性。
4.一致性实现原理
可以说,一致性是事务追求的最终目标。前面提到的原子性、持久性和隔离性,都是为了保证数据库状态的一致性。此外,除了数据库层面的保障,一致性的实现也需要应用层面进行保障。实现一致性的措施包括:
-
保证原子性、持久性和隔离性,如果这些特性无法保证,事务的一致性也无法保证。
-
数据库本身提供保障,例如不允许向整形列插入字符串值、字符串长度不能超过列的限制等。
-
应用层面进行保障,例如如果转账操作只扣除转账者的余额,而没有增加接收者的余额,无论数据库实现的多么完美,也无法保证状态的一致。