数据库事务和事务的隔离级别
前言
什么是事务?事务是由一系列对系统数据的访问与更新的操作所组成的一个程序执行逻辑单元,在狭义上,我们所说的事务指的是数据库事务。
事务的特点
当应用程序并发访问数据库中的数据时,事务能够在这些应用程序中,提供一个隔离方法,用来防止并发操作的互相干扰。另外,事务能够保证了一个从失败中回滚到操作之前的初始状态,保证了数据库在异常情况下,依然能够保持数据一致性的方法。
事务具有四个特征,分别是原子性,一致性,隔离性,持久性,简称为事务的ACID特性。
原子性:Atomicity
事务中包含的各项操作在一次执行过程中,只允许出现两种状态。1.全部成功执行,2.全部不执行。在一个事务中有A,B,C,D四个操作,执行的结果要么四个操作全部执行成功,要么四个操作全部不执行,同时在执行C操作时,出现了异常,此时已经成功执行了A和B,AB的操作都将会被撤销并回滚。
一致性:Consistency
事务的一致性指的是事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性的状态,即,事务执行的结果必须是使数据库从一个一致性状态变到另外一个一致性状态,因此,当数据库只包含成功事务提交的结果时,就说明数据库处于一致性的状态。而当数据库系统在运行过程中发生故障,有些事务尚未完成就已经中断,这些未完成的事务对数据库的修改有一部分已经写入物理数据库,此时,数据库就处于一种不正确的状态,或者说是不一致的状态。
隔离性:Isolation
在并发环境中,并发的事务是相互隔离的。一个事务的执行 不能 被其他事务所干扰,不同的事务 并发操纵相同的数据时,每一个事务都有各自的完整数据空间,即一个事务内部的操作并不会影响其他的并发事务。并发执行的各个事务之间不能相互干扰。
持久性:Durabliity
事务的持久性也被称为永久性,一个事务一旦提交,对数据库中对应数据的状态变更是一个永久性的状态,除非另外有其他事务将数据再变更为其他的状态。
事务并发带来的问题
脏读:一个事务读取到了另外一个事务没有提交的数据。举个栗子,银行取钱,账户余额有1000元钱,现在开启事务A,登录银行账户,此时切换至事务B,事务B取走100元,此时事务还没有提交,事务切回到A,读取到账户余额为900元,这就是脏读,读取到事务没有提交的数据。
不可重复读:在一个事务中,查询了两次数据,两次查询的数据不一致的情况就是不可重复读。银行取钱,账户余额有1000元,现在开启事务A,登录银行账户,查询到余额为1000元,此时切换至事务B,开启事务,取走100元,提交,账户实际余额为900元。切换回事务A,第二次查询余额900元和第一次查询不一致的情况就是 不可重复读。
幻读:在一个事务里面的操作中发现了未被操作的数据。银行取钱,账户消费流水总共有100条明细,现在开启事务A,增加一条消费明细,未提交,此时切换至事务B,B开启事务,增加了10条消费流水,事务提交,此时切换回事务A,A在提交时,发现了多出来的10条记录。好像出现了幻觉。
事务的隔离级别
在标准的sql规范中,定义了4个事务的隔离级别。不同的隔离级别对事务的处理不同。隔离级别有未授权读取,授权读取,可重复读取,串行化。
未授权读取
未授权读取也被称为读未提交(read uncommited)。这个隔离级别最低,同时允许脏读取,不可重复读,幻读。
授权读取
授权读取也被称为读已提交(read commited)。和未授权读取非常的接近,能够防止脏读,但是不能解决 重复读和幻读。
可重复读取
可重复执行(repeatable read),保证事务处理的过程中,多次读取同一个数据时,值和事务开启的时刻是完全一致的,因此这种事务级别禁止了不可重复读和脏读,但是有可能出现幻读。
串行化
串行化(serializable),是事务隔离级别最高的,它要求所有的事务都被串行执行,即事务只能一个接一个的处理,不能并发的执行。
画了一张表格总结一下:
需要开发者注意,事务的隔离级别越高,就越能保证数据的完整性和一致性。但是对于并发的性能来说,影响也是很巨大的,因此我们常用数据的的隔离级别是可重复读取repeatable read。
以mysql数据库为例,查看数据库隔离级别select @@tx_isolation,如下图所示是mysql的数据隔离级别:
更改当前会话事务隔离级别:set session transaction isolation level serializable
更改全局事务隔离级别:set global transaction isolation level serializable