事务的特性
ACID即原子性,一致性,隔离性,持久性
- **原子性(Atomicity):**原子的概念就是不可分割,你可以把它理解为组成物质的基本单位,也是我们进行数据处理操作的基本单位。
- **一致性(Consistency):**数据库在进行事务操作后,会由原来的一致状态,变成另一种一致的状态。也就是当事务提交后,或者当事务发生会滚后,数据库的完整性约束不能被破坏。
- **隔离性(Isolation):**每个事务都是彼此独立的,不会受到其他事务的执行影响,也就是说一个事务在提交之前,对其他事务都是不可见的。
- **持久性(Durability):**事务提交之后对数据的修改是持久性的,即使在系统出故障的情况下,数据的修改依然有效的。因为当事务完成,数据库的日志就会被更新,这时,可以通过日志,让系统恢复到最后一次成功更新的状态。
原子性是基础,隔离性是手段,一致性是约束条件,持久性是我们的目的。
隔离性-隔离级别
异常
-
**脏读dirty read:**读到了其他事务还没有提交的数据。
事务A 事务B 开启事务A 开启事务B 执行 SELECT v FROM T WHERE id = 1
得到结果v=1
执行 update t set v = v + 1 where id = 1
再次执行 SELECT v FROM T WHERE id = 1
得到结果v=2
提交事务B -
**不可重复读non-repeatable read:**对某数据进行读取,发现两次读取的结果不同,也就是说没有读到相同的内容,这是因为有其他事务对这个数据同时进行了修改或者删除。
事务A 事务B 开启事务A 开启事务B 执行 SELECT v FROM T WHERE id = 1
得到结果v=1
执行 update t set v = v + 1 where id = 1
提交事务B 再次执行 SELECT v FROM T WHERE id = 1
得到结果v=2
-
**幻读phantom read:**事务a根据条件查询得到了n条数据,但此时b事务更改或者新增了M条符合事务a查询条件的数据,这样当事务a再次进行查询的时候发现会有m+n条记录,产生了幻读。
事务A 事务B 开启事务A 开启事务B 执行 SELECT v FROM T WHERE id < 10
得到的结果集条数假设为5条,其中id有 1,2,3,4,5执行 insert into T (id,v) values (6,10)
提交事务B 执行 SELECT v FROM T WHERE id < 10
得到的结果集条数为6条,其中多了一条id=6的结果集
隔离级别
- **读未提交read uncommitted:**一个事务还没提交时,它做的变更就能被别的事务看到。这种情况下,查询是不会使用锁的,可能会产生脏读,不可重复读,幻读等情况。
- **读提交read committed:**一个事务提交之后,它做的变更才能被别的事务看到。可能会产生不可重复读,幻读。想要避免,需要编写带锁的sql语句。
- **可重复读repeatable read:**一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据一致。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。无法避免幻读。
- **串行化serializable:**对于同一行记录,写会加写锁,读会加读锁。当出现读写锁冲突时,后访问的事务必须等前一个事务执行完成,才能继续执行。可以解决事务读取中所有可能出现的异常情况,但是牺牲了系统的并发性。
脏读 | 不可重复读 | 幻读 | |
---|---|---|---|
读未提交 | √ | √ | √ |
读提交 | × | √ | √ |
可重复读 | × | × | √ |
串行化 | × | × | × |
×:表示不可能产生的问题
√:表示可能会产生的问题
事务A | 事务B |
---|---|
开启事务A,执行select v from T where id = 1; ,得到值,记为V1 | 开启事务 |
执行update T set v = v + 1 where id = 1 将1改成2 | |
再次执行select ,查询得到的值记为V2 | |
提交事务 | |
再次执行select ,查询得到的值记为V3 | |
提交事务 | |
再次执行select ,查询得到的值记为V4 |
- 读未提交,则v1=2,这时候事务B虽然没有提交,但是结果已经被a看到了,因此,v2=2,v3=2,v4=2;
- 读提交,v1 = 1,v2=1。事务b的更新也是在提交后才能被a看到,所以v3=2,v4=2;
- 可重复读,v1 = 1,v2=1,v3=1,v4 =2之所以v2=1,v3=1,遵循的是:事务在执行期间看到的数据前后必须是一致的。
- 串行化,事务b执行将1变成2的时候,会被锁住,直到a提交后,b才能继续执行,所以从a的角度,v1 = 1,v2 = 1, v3 = 2,v4=2;
事务控制相关语句
start transaction
或者begin
,作用是显式开启一个事务。commit
:提交事务,当事务提交后,对数据库的修改是永久性的。rollback/rollback to [savepoint]
:撤销正在进行的所有没有提交的修改,或者将事务会滚到某个保存点。savepoint
:在事务中创建保存点,方便后续针对保存点进行回滚,一个事务中可以存在多个保存点。release savepoint
:删除某个保存点。set transaction
:设置事务的隔离级别。
oracle默认是不自动提交,Mysql是默认自动提交,可以修改
set autocommit = 0; —-0是关闭,1是开启
set @@comletion_type = 1;
comletion_type=0
:这是默认情况,也就是当我们执行commit
的时候会提交事务,在执行下一个事务时,还需要我们使用start transaction
或者Begin
来开启。comletion_type=1
: 当我们提交事务后,相当于执行了commit and chain
,也就是开启了一个链式事务,即当我们提交时候之后会开启一个相同的隔离级别的事务。comletion_type=2
:commit and release
,会自动与服务器断开连接。
注意
1.oracle数据库的默认隔离级别是读提交,mysql默认的是可重复读。因此对于一些从oracle迁移到mysql的应用,为保证数据库隔离级别的一致,一定要记得将mysql的隔离级别设置为读提交。
配置方式是将启动参数transaction_isolation设置为READ_COMMITTED;
show variables like ‘transaction_isolation’;
2.幻读和不可重复读的区别
- 幻读的在新增或者删除行记录的时候产生的现象,导致两次读取的记录条数不一致。
- 不可重复读是由于修改了某条数据,导致两次读取的数据不一致。