MySQL字符集引起的锁表、唯一索引重复问题
唯一索引冲突
原因:
传入的参数字符集与字段字符集不一致(如参数是 latin1,字段是 utf8mb4),MySQL 可能无法使用索引,转而进行全表扫描
当需要在不同字符集之间进行转换时(如连接查询中两表字段字符集不同),MySQL 会消耗额外资源进行转换,可能导致事务执行时间变长。事务持有锁的时间延长,会增加与其他事务的锁竞争概率,间接引发锁等待或表级锁升级。
解决:
设置字段字符集
在创建数据库、表或修改现有表结构时指定字符集
-
创建数据库时指定字符集
当创建新数据库时,你可以在 CREATE DATABASE 语句中指定字符集,例如使用 utf8mb4 字符集:CREATE DATABASE mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
-
创建表时指定字符集
在创建新表时,你可以在 CREATE TABLE 语句中为表和它的字段指定字符集。例如:CREATE TABLE mytable (id INT AUTO_INCREMENT,name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin,PRIMARY KEY (id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
这里,
CHARACTER SET utf8mb4 COLLATE utf8mb4_bin
指定了字段的字符集和校对规则。 -
修改现有表字段的字符集
如果你需要修改现有表的字段字符集,可以使用 ALTER TABLE 语句:ALTER TABLE mytable MODIFY name VARCHAR(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
-
转换整个数据库的字符集
如果你想转换整个数据库的默认字符集(例如,从 latin1 转换为 utf8mb4),你可以这样做:转换表字符集:
-- 当前的字段都会被重新定义为新的字符集和排序规则,从而可能导致数据转换或损失 ALTER TABLE tablename CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_bin; -- 省略 CONVERT TO 只需修改表的默认字符集,不会影响已有字段的字符集和排序规则。只有在将来的字段添加时,新的字段才会采用指定的字符集和排序规则 ALTER TABLE tablename CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
转换数据库默认字符集:
首先,你需要确保所有的表都已经转换。然后,你可以修改数据库的默认字符集:
ALTER DATABASE mydatabase CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;
注意事项
- 在转换字符集之前,确保你的数据不会因为这种转换而丢失或损坏。特别是当涉及到校对规则(collation)时,某些字符在不同校对规则下可能会有不同的排序或比较行为。
- 对于已经存在的数据,使用
CONVERT TO CHARACTER SET
语句可以帮助转换数据,但这通常不改变列的校对规则。如果需要改变校对规则,需要单独指定。 - 在高流量的生产环境中进行此类操作前,最好在测试环境中进行充分的测试。
- 确保 MySQL 服务器版本支持 utf8mb4 字符集,因为这是从 MySQL 5.5.3 版本开始引入的。使用
SHOW CHARACTER SET;
可以查看支持的字符集列表。