事务是数据库管理系统( DBMS )执行过程中的一个逻辑单位 ,由一个有限的数据库操作序列构成。这里面有两个关键点 ,第一个 ,它是数据库最小的工作单元 ,是不可以再分的。第二个 ,它可能包含了一个或者一系列的 DML 语句 ,包括 insert delete update。(单条 DDL( create drop)和 DCL(grant revoke )也会有事务)
简单来说就是一个或多个语句的集合,就是事务。
事务是以数据结构+算法结合的。
当在执行事务,突发崩溃,数据库会全部回滚。
我们执行的每条命令,也算事务,只不过平常我们的事务只有一条。
原子性(A) 一致性(C) 隔离性(I) 持久性(D) 总称ACID
只要做到ACD就能C
- 原子性:一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中 间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个 事务从来没有执行过一样。
- 一致性:在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完 全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工 作。
- 隔离性:数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务 并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交( Read uncommitted )、读提交( read committed )、可重复读( repeatable read )和串行化 ( Serializable )
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
show variables like 'autocommit';查看事务提交方式(默认是自动提交)
set autocommit=0;关闭默认提交
set autocommit=1;开启默认提交
当我们执行更新(修改)语句时,MySQL会写入日志(mysql不会立刻刷新到硬盘,而是会写入事务日志(transaction log)中,等待合适的时机写入硬盘)重新连接后,执行后的数据依旧存在。
而手动提交时,不会自动提交,必须执行commit语句手动提交。如果发送客户端崩溃或者断开连接时,数据库会全部回滚。
注意:set autocommit=0;修改手动提交只对当前会话生效,当我们重新打开时,会默认修改为自动提交
start transaction与begin时相同的,同样是开启一个事务
savepoint 保存点名;(可以有多个保存点)
rollback;回滚保存点 默认全部回滚
rollback 保存点名 回滚到指定的保存点 也就是回滚至保存点不执行的时候。
注意:结束事务之后,是无法回滚的,保证了事务的持久性。
commit;结束事务
当开启事务时,未结束事务时,客户端发生异常,mysql会自动全部回滚,这体现事务的原则性,要么全部做完,要么什么都不做。
autocommit是否自动提交是不会影响用户手动开启事务的。
存储引擎 InnoDB支持事务 MyISAM不支持事务
数据库中,为了保证事务执行过程中尽量不受干扰,就有了一个重要特征:隔离性
数据库中,允许事务受不同程度的干扰,就有了一种重要特征:隔离级别
- 读未提交【Read Uncommitted】: 在该隔离级别,所有的事务都可以看到其他事务没有提交的 执行结果。(实际生产中不可能使用这种隔离级别的),但是相当于没有任何隔离性,也会有很多 并发问题,如脏读,幻读,不可重复读等,我们上面为了做实验方便,用的就是这个隔离性。
- 读提交【Read Committed】 :该隔离级别是大多数数据库的默认的隔离级别(不是 MySQL 默 认的)。它满足了隔离的简单定义:一个事务只能看到其他的已经提交的事务所做的改变。这种隔离 级别会引起不可重复读,即一个事务执行时,如果多次 select, 可能得到不同的结果。
- 可重复读【Repeatable Read】: 这是 MySQL 默认的隔离级别,它确保同一个事务,在执行 中,多次读取操作数据时,会看到同样的数据行。但是会有幻读问题。
- 串行化【Serializable】: 这是事务的最高隔离级别,它通过强制事务排序,使之不可能相互冲突, 从而解决了幻读的问题。它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争 (这种隔离级别太极端,实际生产基本不使用)
隔离级别如何实现:隔离,基本都是通过锁实现的,不同的隔离级别,锁的使用是不同的。常见有,表 锁,行锁,读锁,写锁,间隙锁(GAP),Next-Key锁(GAP+行锁)等。
当一个会话事务还没结束时,另一个会话就能看到事务修改的数据,这叫脏读,一般这种会发生在读未提交级别。
select @@global.tx_isolation;
select @@session.tx_isolation;
select @@tx_isolation;
会话隔离只会隔离当前会话
全局隔离会隔离所有会话
(设置后需要重新登录,才会生效)
mysql> set global transaction isolation level read uncommitted;
设置全局为读未提交
会话1
会话2
可以看到会话1的事务还未结束,而会话2就可以查看到会话1事务执行的语句,这叫脏读。
几乎没有加锁,虽然效率高,但是问题太多,严重不建议采用。
set global transaction isolation level read committed;
会话1
可以看到,会话1事务还未结束时,会话2读取不到的。
会话1
会话2
两个会话事务同时进行,会话1事务的结束,影响到了会话2的事务,原本是查不到数据的,会话1事务结束,影响到了事务2,这叫不可重复性,是个问题。
set global transaction isolation level repeatable read;
会话1
会话2
可以看到,即使会话1事务结束,也不会影响到会话2的事务,重复体现了隔离性
set global transaction isolation level serializable;
会话1
会话2
可以看到,会话同时操作一个表时,后操作的事务会被阻塞。
对所有操作全部加锁,进行串行化,不会有问题,但是只要串行化,效率很低,几乎完全不会被采用
实际最常用的是可重复读【Repeatable Read】,mysql默认的也是可重复读,RR一般不要更改
表中可重复读会出现幻读,但在MySQL中是不会出现的。