目录
事务:数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,是一个不可分割的工作单位。
特点:
-
MySQL中只有InnoDB数据库引擎支持事务。
-
实物能够保证数据的安全性和完整性。
-
事务用来管理 insert,update,delete 语句。
事务特性(ACID)
原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要不全部失败。
一致性(Consistency):事务执行前后,数据库的完整性没有被破坏。
也就是说,写入的数据完全符合所有的预设规则。
隔离性(Isolation):数据库系统提供的隔离机制,用来保证在多个事务并发运行时,各个事务都能独立安全的执行。
持久性(Durability):事务一旦提交或者回滚,它对数据库的改变是永久的。
并发事务问题
脏读:一个事务读到了另外一个事务还没有提交的数据。
不可重复读:一个事务先后读取同一条记录,结果却不同。
幻读:一个事务查询一条记录时,对应的数据行不存在,但当它向该数据行插入数据时,又发现这条数据已经存在。
事务隔离级别
在并发环境下,数据库为了保证数据的安全可靠,设置了隔离级别。顾名思义,就是将事务隔离开来,使得各个事务可以独立的执行。
读未提交:事务可以查询到其他事务修改过的数据(还未提交事务)。
会造成脏读、不可重复读以及幻读问题。
读已提交:事务可以查询到其他事务提交过的数据。
可以解决脏读问题,不能避免不可重复读以及幻读问题。
可重复读:事务在前后查询同一个数据时,得到的结果始终一致。(即使其他事务修改过数据)
是MySQL默认的事务隔离级别。可以解决不可重复读问题,但不能解决幻读问题。
可串行化:最高合理级别,在该隔离级别下,事务串行化执行。
可以解决所有问题。安全保障最可靠,但是性能也最低。
总结:事务隔离级别由高到低。隔离级别越高数据越安全,但是性能会越差。因此选择隔离级别的时候需要根据特定的场景选择。mysql中默认的事务隔离级别是可重复读。
事务实现原理
一致性实现:是依靠原子性、持久性和隔离性。也就是说,只要能保证其他三种特性,那么一致性就可以实现。
原子性实现:原子性实现依赖的是undo log(重做日志),每次修改数据时,都会往undo log中保存与其反向的操作。需要回滚时,执行反向操作。
原子性实现的关键在于事务需要回滚时,所有数据能够恢复到事务执行前的样子。
持久性实现:每次修改数据时,将操作记录在redo log(重做日志)中,吐过服务器意外宕机,等服务器恢复后,还可以根据redo log恢复数据。
InnoDB是以页来存储,而任何数据修改操作,都先要从硬盘中加载到数据所在的那一整页到内存(buffer pool)中,然后修改数据后不会立即刷新磁盘,而是等到一定时间后才会刷新页面(涉及到I/O,为了保证性能)。 在这期间,如果服务器宕机,那么保存在buffer pool中的数据就会遗失。
因此,引入了redo log,修改完数据后,将操作记录在日志中,即使机器崩溃也能根据redo log来恢复。
隔离级别实现原理(MVCC):
MVCC(多版本并发控制 Multi-Version Concurrent Control):是MySQL提高性能的一种方式,根据undo log和版本链,实现隔离级别(主要针对读已提交和读未提交),让各个事务可以并发执行。
MVCC工作原理
MVCC 是通过在每行记录后面保存两个隐藏的列来实现的。一个保存了行的事务 ID(TRX_ID),一个保存了行的回滚指针(ROLL_PT)。
trx_id:每次对某记录进行改动时,都会把对应的事务 id 赋值给 trx_id 隐藏列。
roll_pt:每次对记录进行改动时,都会把旧的版本写入到 undo 日志中,然后这个隐藏列就相当于一个指针,可以通过它来找到该记录修改前的信息。
当前读:每次读数据时,都会给版本链拍照,所以读到的数据是最新的(已提交)。
快照读:当一个事务第一次查询时,会给版本链拍照,之后的查询都会在这张“照片”里读取数据。