一、什么是事务
事务(Transaction) 是并发控制的基本单位。所谓的事务,它是一个操作序列,这些操作要么都 执行,要么都不执行,它是一个不可分割的工作单位。事务是数据库维护数据一致性的单位,在每 个事务结束时,都能保持数据一致性。
二、事务的特性
ACID,分别是原子性、一致性、隔离性和持久性。
1. 原子性 Atomicity
一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
2. 一致性 Consistency
在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
3. 隔离性
数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
4. 持久性
事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。
三、事务的隔离级别
事务的隔离级别的严格程度从上到下依次为
- 读未提交(Read uncommitted)
- 读提交(read committed)
- 可重复读(repeatable read)
- 串行化(Serializable)
1.读未提交(Read uncommitted)
一个事务读取到其他事务未提交的数据,是级别最低的隔离机制。
2.读提交(read committed)
一个事务读取到其他事务提交后的数据
3.可重复读(repeatable read)
一个事务对同一份数据读取到的相同,不在乎其他事务对数据的修改
4. 串行化(Serializable)
事务串行化执行,隔离级别最高,牺牲了系统的并发性
五、因为事务可能出现的问题
1. 脏读
事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据。
2. 不可重复读
事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3. 幻读
同一事务中对同一范围的数据进行读取,结果却多出了数据或者少了数据,这就叫幻读。(如同一事务对id<10的范围进行2次查询,第一次出现id=8、9的两条数据,第二次出现id=7、8、9的3条数据)。
六、四种隔离级别对脏读、不可重复读、幻读的影响
脏读 | 不可重复读 | 幻读 | |
读未提交(Read uncommitted) | * | * | * |
读提交(read committed) | * | * | |
可重复读(repeatable read) | * | ||
串行化(Serializable) |
七、Yii2中如何使用事务
1. 源码位置和解读
Yii2的事务相关代码的位置是vendor/yiisoft/yii2/db/Connection.php
/** * Starts a transaction. * @param string|null $isolationLevel The isolation level to use for this transaction. * See [[Transaction::begin()]] for details. * @return Transaction the transaction initiated */ public function beginTransaction($isolationLevel = null) { $this->open(); if (($transaction = $this->getTransaction()) === null) { $transaction = $this->_transaction = new Transaction(['db' => $this]); } $transaction->begin($isolationLevel); return $transaction; }
其中设定事务隔离类型的方法如下
/** * Sets the isolation level of the current transaction. * @param string $level The transaction isolation level to use for this transaction. * This can be one of [[Transaction::READ_UNCOMMITTED]], [[Transaction::READ_COMMITTED]], [[Transaction::REPEATABLE_READ]] * and [[Transaction::SERIALIZABLE]] but also a string containing DBMS specific syntax to be used * after `SET TRANSACTION ISOLATION LEVEL`. * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels */ public function setTransactionIsolationLevel($level) { $this->db->createCommand("SET TRANSACTION ISOLATION LEVEL $level")->execute(); }
通过注释我们可以发现四种隔离类型分别通过常量设置
- Transaction::READ_UNCOMMITTED
- Transaction::READ_COMMITTED
- Transaction::REPEATABLE_READ
- Transaction::SERIALIZABLE
常量所在位置vendor/yiisoft/yii2/db/Transaction.php
/** * A constant representing the transaction isolation level `READ UNCOMMITTED`. * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels */ const READ_UNCOMMITTED = 'READ UNCOMMITTED'; /** * A constant representing the transaction isolation level `READ COMMITTED`. * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels */ const READ_COMMITTED = 'READ COMMITTED'; /** * A constant representing the transaction isolation level `REPEATABLE READ`. * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels */ const REPEATABLE_READ = 'REPEATABLE READ'; /** * A constant representing the transaction isolation level `SERIALIZABLE`. * @see http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels */ const SERIALIZABLE = 'SERIALIZABLE';
2. 业务逻辑中开始事务
先上代码,如下是一般业务开启事务的基本用法。
$transaction = Yii::$app->db->beginTransaction(); try { //这里进行对model的读写操作 $transaction->commit(); return true; }catch(\Exception $e) { $transaction->rollBack(); return false; }
基本逻辑为
- 开启事务
- try catch 对异常进行捕获
- 如果没有捕获异常就在最后调用提交
$transaction->commit();
- 如果捕获异常就回滚
$transaction->rollBack();
八、总结
开发人员对事务的掌握和理解是必须的,并且在复杂的业务中也必须掌握事务的用法,以此来保证业务数据的一致性。