有这样三张表,三张表主键都是 stu_num:
起因是发现返回 apply 记录的 JSON 接口有一个用户字段重复了,该接口查询是:
SELECT ... FROM apply a LEFT JOIN info i ON a.stu_num=i.stu_num
排查后发现 apply 中多了一个全角stu_num
的记录,1111
,unicode \uFF11
。但插入 apply 表的stu_num
是从 session 中取的,session 是在登录时设置的,登录验证逻辑:
uname, pwd = request.post_form.get();
if (hash(pwd) == sql_exec('SELECT pwd FROM auth WHERE uname=?', uname))
session.set('uname', uname);
最后结合 log 发现是用户登录时提交了全角的数字 id,而由于auth
表的字符集,uname='1111'
时将uname='1111'
的记录 SELECT 出来了,然后将全角字符设置进了 session 里,在 apply 时被插入了 apply 中
其实挺好奇用户用的什么浏览器 or 输入法会输入全角的数字
插曲
debug 过程中发现了一些以前没有注意到的,关于 MySQL COLLATE
排查时执行SELECT count(*) FROM apply WHERE stu_num='1111';
只返回了一条记录
而 bug 成因是SELECT pwd FROM auth WHERE uname='1111'
返回了stu_num=1111
的记录。测试后是因为字符集 COLLATE 导致的,utf8mb4 存在将全角转换为半角的性质,而 utf8 的utf8_general_ci
却没有这种性质
且查询 apply 的接口之所以 SELECT 出了两条记录,是因为 JOIN 操作 ON 判断的两张表中有一张表的字符集有转换全角的性质,修改 info 表字符集为 utf8 后再 join apply 表则只能 SELECT 出1111
一条记录了
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.