本文未做特别说明的,指同时适用于 MySQL 5.7 和 MySQL 8.x。
先说结论:
在 MySQL 中,数据库对应于数据目录中的目录。数据库中的每个表对应于数据库目录中的至少一个文件(也可能更多,具体取决于存储引擎)。触发器也对应于文件。因此,底层操作系统的大小写敏感度会影响数据库、表和触发器名称的大小写敏感度。这意味着此类名称在 Windows 中不区分大小写,但在大多数 Unix 版本中区分大小写。一个值得注意的例外是 macOS,它基于 Unix,但使用不区分大小写的默认文件系统类型 (HFS+)。
列、索引、存储过程和事件名称在任何平台上都不区分大小写,列别名也不区分大小写。
表和数据库名称如何存储在磁盘上以及如何在 MySQL 中使用受到 lower_case_table_names
系统变量的影响,但该变量不影响触发器标识符的大小写敏感性。
lower_case_table_names
在 Unix 上,默认值为 0。在 Windows 上,默认值为 1。在 macOS 上,默认值为 2。
值 | 含义 |
---|---|
0 | 表和数据库名称使用以大小写敏感的形式存储在磁盘上,名称比较(比如查询)时区分大小写。如果在文件名不区分大小写的系统(例如 Windows 或 macOS)上运行 MySQL,则不应将此变量设置为 0 。如果在不区分大小写的文件系统上强制将变量 lower_case_table_names 设置为 0,并在基于 MyISAM 数据引擎的表使用不同的字母大小写访问表名,则可能会导致索引损坏。 |
1 | 表名称以小写形式存储在磁盘上,名称比较不区分大小写。MySQL 在存储和查找时将所有表名转换为小写。此行为也适用于数据库名称和表别名。 |
2 | 表和数据库名称使用以大小写敏感的形式存储在磁盘上,但 MySQL 在查找时将它们转换为小写。名称比较不区分大小写。这仅适用于不区分大小写的文件系统!基于 InnoDB 数据引擎的表名和视图名以小写形式存储,正如 lower_case_table_names = 1 的情况。 |
另外需要注意的一点是,在 MySQL 8 中 lower_case_table_names
变量只能在MySQL服务器初始化时配置,初始化后不允许修改。所以,如何配置该参数要提前规划好,防止后续修改时需要数据迁移,导致其他问题。
通俗讲字符集就是字符码的集合,在 MySQL 中字符集的选择影响字符码的存储,字符集选择不好不仅影响存储,连展示都会有问题,例如乱码。
在业务中常用的字符集是 UTF-8 字符集,MySQL 有两种这样的字符集:utf8、utf8mb4,它们的区别如下:
UTF-8
的 4 Byte 编码不支持,例如 emoji。而字符的排序规则决定了字符在比较、排序时以及大小写敏感的规则。涉及字符比较的操作均与其相关,例如:排序、分组、索引、比较(=、>、<等)。
在 MySQL 中字符集的排序规则,决定了字段是否大小写敏感。这些排序规则一般以相关的字符集名开始,通常包括一个语言名,并且以 _ci
、_cs
或 _bin
结束 。
举例来说,当使用 utf8mb4
字符集,默认的字段排序规则是 utf8mb4_general_ci
,即字符大小写不敏感。
-- 所有字段都是 utf8mb4 字符集,且均使用 utf8mb4_general_ci 排序规则
create table user(
id int(11) not null auto_increment,
username varchar(127) default null,
nickname varchar(127) default null,
primary key (id),
unique key uniq_idx_username (username)
) engine=innodb default charset=utf8mb4;
我们可以插入几条数据进行测试:
INSERT INTO `user` (`username`) VALUES ('user');
INSERT INTO `user` (`username`) VALUES ('User');
INSERT INTO `user` (`username`) VALUES ('USER');
使用查询语句查询 username 为全部小写的 user 的用户,结果三条记录全部都查询到了,这是因为此时所有字段是大小写不敏感的。
mysql> SELECT username from user where username = 'user';
+----------+
| username |
+----------+
| user |
| User |
| USER |
+----------+
3 rows in set
那么,我想要只搜索出 username 为 user 的用户该怎么做呢?
解决方案就是使用 BINARY
关键字来指定字符字段的排序规则:
mysql> select * from user where BINARY username ='user';
+----+----------+
| id | username |
+----+----------+
| 1 | user |
+----+----------+
1 row in set
这种方式相对较简单,不用改动表结构,只需在需要区分查询的字段前加上关键字。但这种方式也是有缺点的,每次写查询的时候都要注意加关键字,而且可能需要改动较多的代码。
另一种方式是在建表时就对 username
字段进行限制:
-- 均使用 utf8mb4_general_ci 排序规则
CREATE TABLE USER (
id INT (11) NOT NULL auto_increment,
username VARCHAR (127) BINARY NOT NULL,
nickname VARCHAR (127) DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uniq_idx_username (username)
) ENGINE = INNODB DEFAULT charset = utf8mb4;
如果需要整个表都是大小写敏感的,可以在创建表时使用 utf8mb4_bin
排序规则。
create table user(
id int(11) not null auto_increment,
username varchar(127) default null,
nickname varchar(127) default null,
primary key (id),
unique key uniq_idx_username (username)
) engine=innodb default charset=utf8mb4 COLLATE=utf8mb4_bin;
-- 指定 COLLATE=utf8mb4_bin 即可
如何设置 lower_case_table_names
参数?
对于 lower_case_table_names
参数设置为 0 可能会带来哪些问题呢?
比如说:一位同事创建了 Test 表,另一位同事在写程序调用时写成了 test 表,则会报错不存在,更甚者可能会出现 TestDb 库与 testdb 库共存,Test 表与 test 表共存的情况,这样就更加混乱了。所以为了实现最大的可移植性和易用性,我们可以采用一致的约定,例如始终使用小写名称创建和引用库表。也可以将 lower_case_table_names
设为 1 来解决此问题。
另外,上面提到了使用小写的表名,这也是阿里的 Java 开发手册推荐的用法。但如果我们还要考虑其他数据库的兼容,比如 Oracle 呢?这时,保持小写表名就不是一个好想法了。
因为,在 Oracle 中,如果表名和字段名在定义的时候是小写的,那么 SQL 操作时候,表名和字段名是需要用引号括起来的。