laravel中mysql存中文后redis缓存乱码,根源在于mysql服务端、pdo连接及laravel配置三处字符集未统一为utf8mb4;需同步配置my.cnf、database.php及pdo初始化命令,并通过json序列化或直写redis保障编码一致。

当Laravel应用在MySQL中存入中文或特殊符号后,Redis缓存读取时出现乱码、JSON解析失败或序列化异常,本质是数据库字符集与Redis缓存层未协同校准所致——必须同步约束MySQL连接层、PDO声明、Laravel配置三处字符集,否则缓存写入时已携带错误字节流,后续无论Redis如何配置都不可逆。
MySQL服务端与连接层字符集统一
登录MySQL终端执行:SHOW VARIABLES LIKE 'character_set%';,确认character_set_server和collation_server均为utf8mb4与utf8mb4_unicode_ci。若非如此,需在MySQL配置文件my.cnf的[mysqld]段追加:
character-set-server = utf8mb4collation-server = utf8mb4_unicode_ci
重启MySQL服务生效。这一步不完成,Laravel即使配置正确,底层连接仍可能降级为utf8,导致四字节emoji被截断。
Laravel数据库连接强制指定UTF8MB4
打开config/database.php,定位到mysql连接配置的'charset'和'collation'字段:
'charset' => 'utf8mb4','collation' => 'utf8mb4_unicode_ci',
同时在'options'数组中显式追加PDO属性:
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci"
【关键】此行不可省略——它确保每次PDO连接建立时立即执行字符集声明,覆盖MySQL客户端默认行为。缺失该指令时,部分长连接或连接池场景下会出现偶发乱码。
Redis缓存键值编码一致性保障
Redis本身无字符集概念,但Laravel序列化缓存值时依赖PHP环境及序列化协议。若数据库返回UTF-8字符串而Redis存储时被错误转义,问题将暴露在Cache::get()解包阶段。
方法一:禁用自动序列化(适用于纯字符串缓存)
在.env中添加:REDIS_PREFIX=laravel_cache_,并确保config/cache.php中stores.redis.options.prefix与之匹配;随后改用Redis::connection('cache')->set($key, $value)直写,绕过Laravel序列化。
方法二:强制JSON序列化(推荐通用方案)
创建app/Providers/CacheServiceProvider.php,在boot()中重绑定缓存序列化器:
Cache::extend('json_redis', function ($app) { return new Repository( new JsonStore(new RedisStore($app['redis'], 'cache')) );});
再将CACHE_DRIVER=json_redis写入.env。JSON天然强制UTF-8编码,且解包时自动校验BOM,规避序列化污染。
验证联动是否生效
第一步:在Tinker中执行
php artisan tinker
第二步:插入含中文的测试数据
DB::table('users')->insert(['name' => '张三', 'email' => 'zhang@example.com']);
第三步:缓存该记录并立即读取
Cache::put('user_zhang', DB::table('users')->where('name', '张三')->first(), 3600);$cached = Cache::get('user_zhang');dd($cached->name === '张三');
若返回true,说明MySQL字符集、PDO连接、Redis序列化三层已闭环对齐;若为false或报错json_decode(): UTF-8 error,说明某一层仍存在编码降级。











