MYSQL事务

事务的4大特性(ACID)

A - atomicity 原子性

事务不可再分割,事务中的操作要么都发生,要么都不发生。

C - constancy 一致性

事务执行会使数据库从一个一致性状态变换到另一个一致状态。

I - isolation 隔离性

事务的执行不会受到其他事务的干扰。

D - durbility 持久性

事务一旦提交,则会永久改变数据库中的数据。

事务的3大问题

对于两个事务T1和T2。

问题一

脏读。T1读取了已经被T2更新但还没有被提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的。

问题二

不可重复读。T1读取了一个字段后,T2更新了该字段之后,T1再次读取同一个字段的值自然就不同了。

问题三

幻读。T1从一个表中读取了一个字段后,T2在该表中插入/删除了一些新的行之后,如果T1再次读取同一个表,那么就可能多读/少读几行数据。

4个标准的隔离级别

一个事务与其他事务隔离的程度称为隔离级别,数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

  • READ UNCOMMITED(未提交读)

会发生脏读、不可重复读、幻读。

在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。本隔离级别很少用于实际应用,因为它的性能也不比其他级别好多少。读取未提交的数据,也被称之为脏读(Dirty Read)。

  • READ COMMITTED(已提交读)

会发生不可重复读、幻读。

这是大多数数据库系统的默认隔离级别(但不是MySQL默认的)。它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。这种隔离级别也支持所谓的不可重复读(Nonrepeatable Read),因为同一事务的其他实例在该实例处理其间可能会有新的commit,所以同一select可能返回不同结果。

  • 默认REPEATABLE READ(可重复读)

会发生幻读。

这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读 (Phantom Read)。简单的说,幻读指当用户读取某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有新的“幻影” 行。InnoDB和Falcon存储引擎通过多版本并发控制(MVCC,Multiversion Concurrency Control)机制解决了该问题。

简单讲下MVCC吧,MVCC没有实现标准,所以在 MySQL、Oracle、PostgreSQL等都采用不同机制(典型的有乐观并发控制和悲观并发控制)实现了MVCC。可以认为是行级锁的一个变种,但是在很多情况下避免了加锁操作,尽管实现机制不同,但大多都实现了非阻塞的读操作,写操作也只是锁定了必要的行。

  • SERIALIZABLE(串行化)

事务顺序执行,没有并行,完全杜绝幻读。

这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。

隔离级别的操作示例

查看当前隔离级别

SELECT @@tx_isolation;

设置当前MYSQL连接的隔离级别

set session transaction isolation level 【read committed】;

设置数据库系统的全局隔离级别

set global transaction isolation level 【read committed】;

事务的创建

  • 查看事务状态

SHOW VARIABLES LIKE ‘autocommit’

  • 隐式事务

事务没有明显的开启和结束标记,比如,单条insert、update、delete语句。

  • 显式事务

事务具有明显的开启和结束标记,使用的前提必须是先设置自动提交功能为禁用状态 SET AUTOCOMMIT=0,只针对当前会话有效。

事务的开始标记 START TRANSACTION; 结束事务 COMMIT; 或 ROLLBACK;

面试题:Spring中的@Transactional 注解

曾经刚出来工作的时候,做过这样一个题,b发生异常,会回滚吗?

1
2
3
4
5
6
7
8
class test{
@Transactional
void a(){}

void b() {
a();
}
}

不会回滚。类内部方法调用本类内部的其他方法不会引起事务行为,即使被调用的方法使用了 @Transactional 注解进行修饰。

@Transactional 可作用于接口、接口方法、类、类方法、该类所有 pulic 方法将具有该类型的事务属性,同时