事务是保证数据库一致性的核心机制,理解事务和锁对于开发高并发应用至关重要。
ACID 特性
- 原子性(Atomicity):事务中的所有操作要么全部完成,要么全部不完成。
- 一致性(Consistency):事务执行前后,数据库从一个一致状态变为另一个一致状态。
- 隔离性(Isolation):并发事务之间相互隔离,不会互相干扰。
- 持久性(Durability):事务一旦提交,对数据库的改变是永久性的。
隔离级别
| 隔离级别 | 脏读 | 不可重复读 | 幻读 |
|---|---|---|---|
| READ UNCOMMITTED | 可能 | 可能 | 可能 |
| READ COMMITTED | 不可能 | 可能 | 可能 |
| REPEATABLE READ | 不可能 | 不可能 | 可能 |
| SERIALIZABLE | 不可能 | 不可能 | 不可能 |
MySQL 默认使用 REPEATABLE READ,通过 MVCC 和间隙锁解决幻读问题。
锁类型
行锁
InnoDB 默认使用行级锁:
SELECT * FROM users WHERE id = 1 FOR UPDATE;
表锁
LOCK TABLES users WRITE;
UNLOCK TABLES;
间隙锁(Gap Lock)
防止幻读的关键机制,锁定索引记录之间的间隙:
SELECT * FROM users WHERE age > 20 FOR UPDATE;
-- 会锁定 age > 20 的记录以及间隙
Laravel 中的事务
use Illuminate\Support\Facades\DB;
DB::transaction(function () {
$user = User::create(['name' => 'Snowman']);
$user->profile()->create(['bio' => 'Hello']);
});
// 手动控制
DB::beginTransaction();
try {
User::create(['name' => 'Snowman']);
DB::commit();
} catch (Exception $e) {
DB::rollBack();
throw $e;
}
乐观锁与悲观锁
悲观锁
$user = User::lockForUpdate()->find(1);
$user->balance -= 100;
$user->save();
乐观锁
// 在模型中添加 version 字段
class User extends Model
{
protected $versioning = true;
}
$user = User::find(1);
$user->balance -= 100;
$user->save(); // 如果 version 不匹配会抛出异常