- 发帖可能变空内容,邪门暂不知所以然
- 『稷下学宫』新认证方式,24年网站打算和努力目标
主题:【求助】mysql 里面邪门的 utf8mb4 问题 -- 铁手
网站数据库里原来是用的GBK,一直也没什么问题。现在为了支持 emoji,比如 😀 😁 😂 🤣 😃 😄 😅 😆 😉,所以要改为 utf8mb4。
大部分还算顺利,但是在这个过程中碰到一个很邪门的问题。
主要是中文里的全角字符,比如这个全角的数字:203和普通数字 203,在GBK中算是不同的东西,但是在 utf8mb4 里面变成了一样的东西。至少是在作 index 的时候,是同等看待,于是就造成了原来是 unique 的,变得重复了。
试验了一下 utf8 编码,也是同样的问题。
难道说在 utf8 中全角的概念?还是说 mysql 在处理字符集的时候有错误?
https://www.v2ex.com/t/662096
alter table t_unicode convert to character set utf8mb4 collate utf8mb4_bin
除了编码之外,collation决定如何比较字符串和顺序,有多个变种。用错了会造成不能区分大小写全半角,只考虑语意一致性。
https://zudoh.com/mysql/should-use-collation-utf8mb4_bin-as-default
现在的比较的没开width sensitive
https://dev.mysql.com/doc/refman/8.0/en/charset-asian-sets.html
改成
gbk_bin试试?
不行了再上
utf8mb4_bin
这里汇报一下测试结果,看看大家有没有什么想法。@西电鲁丁 @葡萄干 @骆筱 @shinji
首先需要确认的是,内容保存没有问题。输入什么,保存的也是什么。毛病出在索引上。
Collation最早是用 gbk_chinese_ci
以下是直接在库结构上改(不知道 DUMP 出来再 IMPORT 进去会不会有区别)的情况。
如果改成 utf8mb4_general_ci 则全角和半角字符不再被同等看待,解决部分问题。但是出现 e 等同于 é 的情况。以及两个历史遗留的乱码变成等同。
_ci 的意思是 case insensitive,所以这可能就是看似不同,但是被当作相同的原因。
如果改成 utf8mb4_bin 则上述 全角字符问题,e 等同于 é 这两种情况不再存在。那两个乱码问题依旧存在。
现在看来,大概就是只能用 utf8mb4_bin,然后手工修改那两个乱码。
邪门的是,这两个乱码我怎么看都是一样的,不知道在 gbk_chinese_ci 的时候,为什么会被当作不一样。
https://dev.mysql.com/doc/refman/8.0/en/faqs-cjk.html#faq-cjk-how-cjk-sort-unicode-1
建议用utf8mb4_ja_0900_as_cs能解决老版本遗留的问题
不过怎么看都是针对日语的,有兴趣可以试试utf8mb4_zh_0900_as_cs
postgresql 性能强大的多,而且稳如死狗
脚本在这,跑了一下,没有乱码,唯一索引也可以的:
drop table if exists zzIronHand;
create table if not exists zzIronHand (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(25) not null COMMENT '测试铁手问题的字段',
PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=gbk ROW_FORMAT=COMPACT COMMENT='测试铁手问题';
insert into zzIronHand(`name`) values ('203');
insert into zzIronHand(`name`) values ('203');
insert into zzIronHand(`name`) values ('e');
insert into zzIronHand(`name`) values ('é');
select * from zzIronHand;
create unique index idxIronHand on zzIronHand(`name`);
我这版本老了点,是MySQL 5.6的。
- 待认可未通过。偏要看
我就是想从原来的GBK转到 utf8mb4 的其中一种,然后在 unique index上碰到了一些数据错误。
眼下看来,最靠谱大概就是用 utf8mb4_bin 了。
我查来查去的结果,也是有很多人抱怨 mysql 这种字符支持的各种怪异。比如直觉上用 utf8 的,实际上要用 utf8mb4 才行。也有不少人热赞 postgresql 的。
不知道这个学起来难度大不大?我现在用的是 PDO,估计转换起来也不会太多问题。关键是数据库的管理,比如备份之类的,怎么样?
你的这个帖中提到的问题,看来是显示上全角半角分不清。出现这种问题,还真是只能哭了,怎么会想的到呢。
是我看帖不仔细,没理解需求
接上面的脚本,我加了这句,把字段的Charset改了:
ALTER TABLE zzIronHand
CHANGE COLUMN `name` `name` varchar(25) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
然后再: select * from zzIronHand;
发现没有码,一切正常,索引也没报错。
如果换了其他collate, 尤其是那些ci结尾的,就会报错,说之前创建的唯一索引不对,这个是正常的,因为ci就是Case Insensitive,把e é当成一样的了。
不过好像MySQL的Charset/Collate是有些历史遗留问题的,可以参考一下这里:https://stackoverflow.com/questions/43644218/why-is-table-charset-set-to-utf8mb4-and-collation-to-utf8mb4-unicode-520-ci