事务
事务是多条DML语句组成为了达到某一特地的任务。
一个完整的事务,需要满足四个属性:
- 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束之后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度,串联性以及后续数据库可以自发地完成预定的工作。
- 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(read uncommitted),读提交(read committed),可重复读(repeatable read)和串行化(Serializable)
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
简称ACID
原子性(Atomicity,或称不可分割性)
一致性(Consistency)
隔离性(Isolation,又称独立性)
持久性(Durability)
事务提交方式
- 手动
- 自动
sql
show variables like 'autocommit'; #查看自动提交
set autocommit=0; #关闭
set autocommit=1; #打开
启动事务
sql
start transaction; #启动
savepoint s1; #设置保存点s1
rollback to s1; #回滚到s1
commit; #提交结束掉事务
begin; #启动事务
如果没有设置保持点rollback会回到最初的状态。
commit之后就无法rollback
- 异常退出事务会自动回滚
- 自动提交不会影响手动的提交
- autocommit会影响单sql语句
- 对于InnoDB单sql也是事务,自动提交
隔离性
数据库中为了保证事务执行过程中尽量不受干扰,就有了隔离性
隔离级别
- 读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。
- 读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。
- 可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。默认级别
- 串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争(这种隔离级别太极端,实际生产基本不使用)
查看与设置隔离性
sql
select @@global.tx_isolation; #查看全局隔离级别
select @@session.tx_isolation; #查看会话(当前)隔离级别
select @@tx_isolation; #查看会话(当前)隔离级别
set session transaction isolation level read committed; #设置会话隔离级别
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ
COMMITTED | REPEATABLE READ | SERIALIZABLE}
如果global和session不一样默认使用session
读未提交:一个正在执行的事务只要插入了没有commit另一个事务就能看到数据,这种现象叫做脏读
读提交:不可重复读,一个读的事务可能会出现重复的数据
可重复读:只有退出mysql重新登录进入事务才能看到修改的内容
串行化:数据库并发性能低,加锁
隔离性更深的理解
读写并发
多版本并发控制(MVCC)是一种用来解决读写冲突的无锁并发控制
三个前置知识:
3个隐藏字段undo 日志read view
三个隐藏列字段DB_TRX_ID:6byte,最近修改(修改/插入)事务ID,记录创建这条记录/最后一次修改该记录的事务IDDB_ROLL_PTR:7byte,回滚指针,指向这条记录的上一个版本(简单理解成,指向历史版本就行,这些数据一般在 undo log 中)DB_ROW_ID:6byte,隐含的自增ID(隐藏主键),如果数据表没有主键,InonoDB会自动以DB_ROW_ID产生一个聚簇索引- 补充:实际上还有一个删除flag隐藏字段,既记录被更新或删除并不代表真的删除,而是删除flag遍历
undo log
简单理解成,就是MySQL中的一段内存缓存区,用来保存日志数据的就行。
read view
read view是事务可见性的一个类,不是事务创建出来,就会有read view.而是当这个事务(以及存在),首次进行快照读的时候,mysql形成read view
- 每个事务都要有自己的事务ID,可以根据事务ID的大小,来决定事务到来的先后顺序
- mysql可能会面临处理多个事务的情况,事务也有自己的生命周期,mysqld要对多个事务进行管理,先描述,后组织。事务也有自己的结构体。