Laravel 11未新增事务隔离级别底层能力,仍依赖PDO与数据库原生支持;推荐使用DB::transactionWithIsolation()传入PDO常量(如PDO::TRANSACTION_READ_COMMITTED),运行时校验更严格,全局配置仍需DB::unprepared()或初始化钩子实现。

Laravel 11 并未新增事务隔离级别的底层能力,它仍依赖 PDO 和 MySQL(或其他数据库)原生支持。所谓“对比”,本质是配置方式更规范、默认行为更明确,而非功能翻新。读写分离与锁机制本身属于不同层级:读写分离是连接路由策略,锁和隔离级别是事务执行时的并发控制手段——二者可共存,但不互相替代。
事务隔离级别设置更清晰,但逻辑没变
Laravel 11 延续了 DB::transactionWithIsolation() 的推荐用法,且文档强调必须传入 PDO 常量(如 PDO::TRANSACTION_READ_COMMITTED),不再接受字符串别名。旧版(如 8.x/9.x)虽也支持该方法,但部分项目误用 'READ COMMITTED' 字符串导致静默失败;Laravel 11 在运行时会更早校验参数类型,提升健壮性。
- 正确写法(Laravel 11 推荐):
DB::transactionWithIsolation(fn () => DB::table('orders')->update(...), PDO::TRANSACTION_READ_COMMITTED) - 旧版可能容忍但不安全的写法:
DB::transactionWithIsolation(..., 'READ COMMITTED')—— 实际未生效,易被忽略 - 全局配置仍需手动干预:Laravel 11 仍未在
config/database.php中提供isolation_level一级配置项,仍要靠DB::unprepared("SET TRANSACTION ISOLATION LEVEL ...")或连接初始化钩子
读写分离下事务强制走主库,新版无例外
从 Laravel 5.4 到 11,只要进入 DB::transaction() 或显式调用 beginTransaction(),所有后续查询(含 SELECT)一律路由到 write 连接。Laravel 11 没放宽这条规则,反而在日志和异常提示中更明确标出“transaction context forces write connection”。
Laravel Cloud(cloud.laravel.com)。此技能用于处理所有 Laravel Cloud 请求,包括搜索和读取数据。只要任务涉及 Laravel Cloud,即使用此技能。
- 常见误操作:在事务里先
DB::table('logs')->where(...)->first()再更新 —— 即使语义是“读”,也会发到主库;不是 bug,是设计 - 想查从库?不行。只能把读提前:
$config = DB::table('settings')->first(); DB::transaction(fn () => ...); - 试图用
DB::connection('mysql')->table(...)->on('mysql_read')在事务内切从库,会直接抛TransactionException
锁机制完全由数据库承担,框架只透传
Laravel 不实现行锁、表锁或 MVCC 版本控制。它只是把 SELECT ... FOR UPDATE、LOCK IN SHARE MODE 这类语句原样交给 MySQL 执行。Laravel 11 和旧版在这点上完全一致,区别仅在于 Query Builder 对锁语法的封装更稳定:
-
DB::table('stocks')->where('id', 1)->sharedLock()->first()→ 生成SELECT * FROM stocks WHERE id = 1 LOCK IN SHARE MODE -
DB::table('stocks')->where('id', 1)->lockForUpdate()->first()→ 生成SELECT * FROM stocks WHERE id = 1 FOR UPDATE - 这些锁是否生效、是否阻塞、是否参与死锁检测,全由 MySQL 的存储引擎(InnoDB)决定,Laravel 不介入
sticky + 隔离级别组合,才是高一致性场景的实用解法
单独设 isolation_level 或开 sticky 都不够。Laravel 11 更强调两者的协同:
-
sticky => true解决“写后立刻读不到”的延迟问题(路由层) -
TRANSACTION_REPEATABLE_READ解决“同一事务中多次读结果不一致”的不可重复读问题(执行层) - 例如用户余额扣减+记录流水:开启
REPEATABLE READ事务,并确保整个流程走主库(sticky自动触发),才能避免中间被其他事务干扰 - 注意:MySQL 默认就是
REPEATABLE READ,Laravel 11 不改变默认值,但鼓励显式声明以提高可维护性










