You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel切换数据库缓存驱动后出现主键重复错误求助

问题描述

将缓存驱动切换为数据库后,Laravel持续抛出如下错误,目前已产生数千条:

PDOException: Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'dbapp_cache_9794540492d50c5a53832f6e31d7ca3fced8f2d2:timer' for key 'cache.PRIMARY' in /app/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:117

我已经禁用了所有用到缓存的路由,但错误还是出现,不清楚Laravel到底在缓存什么。缓存表里全是这类带时间戳的记录。

更新1:切换驱动后的迁移操作

切换缓存驱动后执行了以下迁移代码:

Schema::create('cache', function (Blueprint $table) {
    $table->string('key')->primary();
    $table->mediumText('value');
    $table->integer('expiration');
});

Schema::create('cache_locks', function (Blueprint $table) {
    $table->string('key')->primary();
    $table->string('owner');
    $table->integer('expiration');
});

Schema::table('forms', function (Blueprint $table) {
    $table->index('user_id');
});

Schema::table('respondents', function (Blueprint $table) {
    $table->index('deleted_at');
});

Schema::table('subscriptions', function (Blueprint $table) {
    $table->index('gateway_id');
});

更新2:当前唯一使用缓存的场景

目前代码里唯一用到缓存的地方是数据库锁:

return Cache::lock("subscription_{$subId}")->block(10, function() use($request, $subId){
        
   // 业务代码...

});

问题根源与解决建议

核心原因

这个错误是缓存锁的定时器键并发插入冲突导致的,具体来说:

  1. 缓存锁内部机制:Laravel的Cache::lock()->block()方法会自动生成带:timer后缀的缓存键,用来跟踪锁等待的超时时间。当多个请求同时争抢同一个锁(比如同一个subscription_{$subId})时,都会尝试创建这个:timer键。
  2. 数据库驱动的非原子性:数据库缓存驱动的add操作是“先查后插”的非原子逻辑——高并发下,多个请求会同时通过“键不存在”的校验,然后同时执行插入,直接触发主键重复的约束错误。
  3. 潜在表结构问题:虽然不是直接原因,但如果cache表的key字段长度不够(比如默认string是255字符),可能导致长键被截断,间接引发重复;不过从错误信息看,你的键是完整的,这个可能性较低。

解决方法

  • 优先换用Redis驱动:Redis的SETNX命令是原子性的,能从根源避免这种并发冲突,这也是Laravel缓存锁推荐使用的驱动。
  • 重写数据库缓存驱动的add方法:如果必须用数据库驱动,可自定义驱动,把add操作改成INSERT ... ON DUPLICATE KEY UPDATE的原子逻辑,避免重复插入。
  • 清理现有冲突缓存:先清空cache表中所有带:timer后缀的键,暂时缓解错误。

内容的提问来源于stack exchange,提问作者user3152263

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 11:57:04