MySQL關於 lower_case_table_names 的文檔 https://dev.mysql.com/doc/refman/5.7/en/identifier-case-sensitivity.html
In MySQL, databases correspond to directories within the data directory. Each table within a database corresponds to at least one file within the database directory (and possibly more, depending on the storage engine). Triggers also correspond to files. Consequently, the case sensitivity of the underlying operating system plays a part in the case sensitivity of database, table, and trigger names. This means such names are not case-sensitive in Windows, but are case-sensitive in most varieties of Unix. One notable exception is macOS, which is Unix-based but uses a default file system type (HFS+) that is not case-sensitive. However, macOS also supports UFS volumes, which are case-sensitive just as on any Unix. See Section 1.8.1, “MySQL Extensions to Standard SQL”. The lower_case_table_names
system variable also affects how the server handles identifier case sensitivity, as described later in this section.
1. 原理部分:
MySQL的數據庫名稱、表名稱、觸發器名稱 是對應到 目錄和文件名稱。而在 Linux系統下面,目錄和文件名稱是區分大小寫的,所以默認 數據庫名稱、表名、觸發器名稱也是區分大小寫的。
但是Windows系統下面目錄 和文件名 是不區分大小寫的:
上圖當我們在windows下面建立一個a和A的文件夾時,彈出提示;當我們建立a.txt和A.txt時也彈出提示。
2. 默認值的影響
How table and database names are stored on disk and used in MySQL is affected by the lower_case_table_names
system variable, which you can set when startingmysqld. lower_case_table_names
can take the values shown in the following table. This variable does not affect case sensitivity of trigger identifiers. On Unix, the default value of lower_case_table_names
is 0. On Windows, the default value is 1. On macOS, the default value is 2.
Linux下面 lower_case_table_names 默認是0,Windows下默認是1,MacOS默認是2;
他們的含義如下:
lower_case_table_names=0 庫名表名存儲為給定的大小和比較是區分大小寫的
lower_case_table_names = 1 庫名表名存儲在磁盤是小寫的,但是比較的時候是不區分大小寫
lower_case_table_names=2 庫名表名存儲為給定的大小寫但是比較的時候是小寫的
3. 存在的問題1:
如果從Windows平台遷移到Linux平台,原來的庫名和表名是不區分大小寫的;比如一個user表,他是小寫存儲,但是sql語句里面使用:
select * from user 和 select * from USER 或者 select * from User都是一樣的,因為在查找比較是是不區分大小的;
先要遷移到Linux平台,導入之后 庫名表名也是小寫存儲,但是庫名表名在比較查找時是區分大小寫的,所以:
只有 select * from user是可以找到user表對應的存儲在Linux下的文件的,其他任何形式都是無法找到表的;
解決方法:遷移到Linux平台之后,將 lower_case_table_names 的值改成1;也就是在查找比較時不區分大小寫就可以了;
存在的風險:比如Linux平台原來有 tuser 表和 TUSER表,因為原來是區分大小寫的,他們對應的是不同的表和存儲文件,現在改成不區分大小寫,那么問題就出現了!表名沖突了。不過這種情況比較少見。相對而言還是比較安全的。
4. 存在的問題2:
如果是從Linux平台遷移到Windows平台,原來的庫名和表名是區分大小寫的;現在遷移到Windows平台,不區分大小寫,
比如原來有 tuser 表和 TUSER表,因為原來是區分大小寫的,他們對應的是不同的表和存儲文件,現在改成不區分大小寫,那么問題就出現了!!!表名沖突了!不過這種情況比較少見。
解決方法:遷移到Windows平台之后,將 lower_case_table_names 的值改成0;也就是在查找比較時區分大小寫就可以了;
存在的風險:存儲和比較都是區分大小寫了,比如原來windows平台的 select * from user 和 select * from USER都是合法的,現在導致 select * from USER會找不到表名了!!!
所以從 linux平台遷移到 windows平台是,一般是不需要修改 將 lower_case_table_names 的值改成0的,因為表名沖突的情況及其罕見。從區分大小寫到不區分大小寫在一般情況下面是兼容的。
而且如果windows平台的數據庫存在之前的數據庫,修改之后,導致應用系統的sql找不到表名,這個問題更加嚴重!
5. 建議
-
Use
lower_case_table_names=1
on all systems. The main disadvantage with this is that when you useSHOW TABLES
orSHOW DATABASES
, you do not see the names in their original lettercase. -
Use
lower_case_table_names=0
on Unix andlower_case_table_names=2
on Windows. This preserves the lettercase of database and table names. The disadvantage of this is that you must ensure that your statements always refer to your database and table names with the correct lettercase on Windows. If you transfer your statements to Unix, where lettercase is significant, they do not work if the lettercase is incorrect.Exception: If you are using
InnoDB
tables and you are trying to avoid these data transfer problems, you should setlower_case_table_names
to 1 on all platforms to force names to be converted to lowercase.
如果不存在在不同平台遷移的情況,那么保持默認值即可。
如果存在Linux和Windows平台之間進行遷移的情況,那么在一開始的時候任何平台設置lower_case_table_names=1可以避免問題;
設置lower_case_table_names=1唯一的問題是, show tables 和 show databases 看到的不是你新建表和數據庫時指定的大小寫字母。
6. 總結
0. 其實掌握原理:MySQL的庫名和表名對應到文件目錄和文件,然后Linux區分目錄和文件名稱大小寫,而Windows平台不區分,其他的東西都可以推演處理;
1. 在windows和linux平台之間遷移時,需要修改 lower_case_table_names = 1;而Linux向Windows平台遷移時,一般不需要修改改參數;
2. 在任何平台一開始的時候就設置 lower_case_table_names=1 可以解決平台遷移時存在的問題;
3. 觸發器名稱的比較不是由lower_case_table_names來控制的;