何为事务?
一言蔽之,事务是逻辑上的一组操作,要么都执行,要么都不执行,感觉有点原子性的意思。
何为数据库事务?
简单来说:多个SQL 语句 要么全部执行成功,要么全部不执行 。
# 开启一个事务
START TRANSACTION;
# 多条 SQL 语句
SQL1,SQL2...
## 提交事务
COMMIT;
什么是ACID?
关系型数据库事务都有 ACID 特性:
- 原子性(Atomicity) : [ˌætəˈmɪsəti] ,事务是最小的执行单位,不允许分割。事务的原子性确保动作要么全部完成,要么完全不起作用;
- 一致性(Consistency): [kənˈsɪstənsi] ,执行事务前后,数据保持一致,例如转账业务中,无论事务是否成功,转账者和收款人的总额应该是不变的;
- 隔离性(Isolation): [ˌaɪsəˈleɪʃn],并发访问数据库时,一个用户的事务不被其他事务所干扰,各并发事务之间数据库是独立的;
- 持久性(Durability):[ˌdjʊərəˈbɪləti] , 一个事务被提交之后。它对数据库中数据的改变是持久的,即使数据库发生故障也不应该对其有任何影响。
数据事务的实现原理呢?
我们这里以 MySQL 的 InnoDB 引擎为例来简单说一下。
MySQL InnoDB 引擎
使用 undo log(回滚日志) 来保证事务的原子性
,
使用 redo log(重做日志) 保证事务的持久性
,
通过 锁机制、MVCC 等手段来保证事务的隔离性
( 默认支持的隔离级别是 REPEATABLE-READ )
保证了事务的持久性、原子性、隔离性之后,一致性
才能得到保障。
并发事务带来哪些问题?
1, 脏读(Dirty read):
- 一个事务(A)读取到另一个事务(B)中
未提交的数据
。(B)中事务中数据可能进行了改变,此时(A)事务读取的数据可能和数据库中数据是不一致的,此时认为数据是脏数据,读取脏数据过程叫做脏读。
2. 不可重复读(Unrepeatable read):
- 主要针对的是
某行数据
( 或行中某列
). - 主要针对的操作是
修改操作
. - 两次读取在
同一个事务内
- 当事务A 第一次读取事务后,事务B 对事务A 读取的数据进行修改,事务A 中再次读取的数据和之前读取的数据不一致,过程不可重复读。
3.幻读(Phantom read):
- 主要针对的操作是
新增
或删除
两次事务
的结果.- 事务A 按照特定条件查询出结果,事务B 新增了一条符合条件的数据。事务A 中查询的数据和数据库中的数据不一致的,事务A 好像出现了幻觉,这种情况称为幻读。
事务隔离级别
在多线程并发访问下如何保证访问到的数据具有完整性的?
1 . 读未提交 READ_UNCOMMITTED
:
最低的隔离级别,因为它允许读取尚未提交的数据变更,可能会导致脏读、不可重复读、幻读。
通常情况下不会用到该级别。
2 .已提交读 READ_COMMITTED
:
允许读取已经提交的数据,可以阻止脏读,可能会导致不可重复读、幻读
3 .可重复读 REPEATABLE_READ
:
对 同一字段 的多次读取结果都是一致的,除非数据是被本身事务自己所修改。可以阻止脏读和不可重复读,可能会导致幻读
4 .串行化 SERIALIZABLE
:
最高的隔离级别,完全服从 ACID 的隔离级别。所有的事务依次逐个执行,事务之间完全不可能产生干扰,可以防止脏读、不可重复读,幻读。但是这将严重影响程序的性能。通常情况下不会用到该级别。
MySQL 默认采用的 可重复读REPEATABLE_READ
隔离级别
Oracle 默认采用的已提交读 READ_COMMITTED
隔离级别
事务传播行为.
事务传播行为是为了解决业务层方法之间互相调用的事务问题
当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务(新建事务?在事务中执行?把事务挂起?报异常?)
MANDATORY: [ˈmændətəri],如果当前上下文有事务,加入事务,如果当前上下文没有事务,报错。 即保证→ 调用此方法时必须和上下文在同一个事务里
NEVER: 如果当前上下文有事务,报错; 如果当前上下文没有事务,正常执行。 即保证→ 新的方法在没有事务的上下文中执行
------------------------------------------------------------------------------------------
SUPPORTS: [səˈport],如果当前上下文有事务,加入事务;如果当前上下文没有事务,就在非事务状态下执行。 即 → 无所谓有没有事务的
REQUIRED: (默认值)如果当前上下文有事务,加入事务;如果当前上下文没有事务,新建一个事务。 即保证 → 新的方法必须要有事务
------------------------------------------------------------------------------------------
NOT_SUPPORTED: 如果当前上下文有事务,把当前上下文事务挂起;如果当前上下文没有事务,正常执行。 即保证 → 新的方法在没有事务的环境中执行
REQUIRES_NEW: 如果当前上下文有事务,把当前上下文事务挂起,新建事务;如果当前上下文没有事务,新建事务,执行当前新建事务完成以后,上下文事务恢复再执行。即保证 → 新的方法必须要有独立的事务
------------------------------------------------------------------------------------------
NESTED: [ˈnestɪd],如果当前上下文有事务,创建一个嵌套事务.如果当前上下文没有事务,新建事务
参考:事务的嵌套