最近在阿里雲服務器上部署一個本身寫的小 demo 時遇到一點問題,查看 Tomcat 日誌後定位到問題出如今與數據庫服務器交互的地方,執行 SQL 語句時會返回 指定列.指定名
不存在的錯誤。多方查證後發現原來 MySQL 的標識符大小寫區分規則在 Unix 和 Windows 系統上是不一樣的。爲了解決這個問題我去查看了 MySQL 官方給出的參考手冊後解決,同時爲了學習我參考手冊中對應部分作了一次全面翻譯。html
<!--more-->mysql
先說結論:在 Windows 操做系統中將 MySQL 的系統變量 lower_case_table_names
值修改成 2,並在開發時詳細規定好標識符名的大小寫規則。sql
下面是翻譯文章,原文連接:MySQL :: MySQL 5.6 Reference Manual :: 9.2.2 Identifier Case Sensitivity數據庫
在 MySQL 中,數據庫存儲在文件系統中的 data 目錄。每一個數據庫對應一個子目錄,每張表對應一個子文件(也可能更多,取決於使用的存儲引擎)。觸發器也有對應文件。因此,數據庫、表和底層觸發器是否區分大小寫取決於底層操做系統。也就是說標識符在 Windows 系統中是大小寫不敏感的,在大多數 Unix 系統中是大小寫敏感的。MacOS 是一個特例,雖然它是基於 Unix 的系統,可是其默認文件系統(HFS+)是大小寫不敏感的。不過,MacOS 也支持 Unix 系統都支持的 UFS 文件系統。請參見 1.7.1 MySQL Extensions to Standard SQL 。此外,系統變量 lower_case_table_names
也會影響 MySQL 服務器是否區分標識符的大小寫,本章後續內容會介紹。服務器
須要注意的是,儘管數據庫、表和觸發器名在某些平臺上不區分大小寫,也不該該在一個同一個語句中分別使用大寫和小寫。下面這行語句不會執行由於它同時使用了 my_table
和 MY_TABLE
:ide
SELECT * FROM my_table WHERE MY_TABLE.col=1;
列、索引、存儲例程<sup>①</sup> 、事件名和列的別名不管在什麼操做系統中都不區分大小寫。函數
此外,日誌文件的名稱區分大小寫,這一點和標準 SQL 語言不一樣。學習
默認狀況下,表名在 Unix 系統中大小寫敏感,在 Windows 和 MacOS 中不敏感。下面這行語句在 Unix 系統中不會執行,由於它同時使用 a 和 A 來作表的別名:阿里雲
SELECT col_name FROM tbl_name AS a WHERE a.col_name = 1 OR A.col_name = 2;
可是,在 Windows 操做系統中這行語句是能夠執行的。爲了不這些不一樣引發的問題,最好採用一致的約定,好比建立和使用數據庫和表時都採用小寫字母,這樣的約定會最大程度的提高你代碼的跨平臺性(portability)和易用性(ease)。spa
數據庫和表名在磁盤上如何存儲和使用取決於 lower_case_table_names
系統變量,啓動 MySQL Server 後能夠設置這個變量的值。下表 給出lower_case_table_names
的可選值和對應的含義。改變量的值不會影響觸發器的大小寫區分規則。在 Unix 系統中, lower_case_table_names
默認值爲 0,在 Windows 系統中默認值是 1 。在 MacOS 中默認值爲 2。
Value | Meaning |
---|---|
0 | 數據庫和表名的大小寫取決於 CREATE TABLE 和 CREATE DATABASE 語句中指明的大小寫,標識符名是大小寫敏感的。在 WIndos 或 MacOS 等文件系統大小寫不敏感的操做系統中不該將此變量的值設爲 0,若是強行設置爲 0,而且使用不一樣大小寫的字母訪問使用 MyISAM<sup>②</sup> 引擎的數據表,可能會致使索引損壞。 |
1 | 數據庫和表名以小寫形式存放在磁盤上,標識符名大小寫不敏感。此時 MySQL 執行 SQL 語句時會將全部的數據庫名、表名和表別名轉換成小寫。 |
2 | 數據庫和表名的大小寫取決於 CREATE TABLE 和 CREATE DATABASE 語句中指明的大小寫,可是執行查詢語句時 MySQL 會將其傳化成小寫,這種狀況下標識符名不區分大小寫。這個值僅適用於文件系統大小寫不敏感的操做系統!當使用 InnDB<sup>②</sup> 引擎,數據表的具體表現和值爲 1 時相同。 |
若是你只在一個平臺上使用 MySQL ,通常來講是不用修改 lower_case_table_names
的默認值的。可是在文件系統規則不一樣的平臺上轉移表時可能會發生錯誤。例如,在 Unix 系統中 my_table
和 MY_TABLE
是兩個不一樣的表,可是在 WIndows 系統上是同一個。有兩種方法能夠保證在不一樣平臺上轉移數據時不發生錯誤:
在每一個系統中都設置 lower_case_table_names = 1
,不過這樣設置會致使執行 SHOW DATABASES
和 SHOW TABLES
語句不會正確返回建立時使用的大小寫區分。
在 Unix 系統上設置 lower_case_table_names = 0
,Windows 系統上設置 lower_case_table_names = 2
。這樣能保留數據庫和表名的原始大小寫區分。 使用這種方法,您必須保證在 Windows 系統上執行語句時始終使用正確的大小寫區分。若是大小寫區分不當,將語句轉移到 Unix 系統時會發生錯誤。
**注意:**若是使用 InnDB 做爲引擎,爲了不傳輸數據時發生的錯誤,應該在全部平臺上都設置 lower_case_table_names = 1
從而將標識符強制轉化成小寫。
若是您準備在 Unix 系統中設置 lower_case_table_names = 1
,在設置完成以後、重啓 MySQL Server 以前必須手動將表名修改成小寫。使用 RENAME TABLE
語句完成:
RENAME TABLE T1 TO t1;
若是要修改一個或多個數據庫,請在設置 lower_case_table_names = 1
以前備份,而後刪除數據庫,在設置 lower_case_table_names = 1
以後從新加載數據庫:
使用 mysqldump 備份每個須要從新建立的數據庫:
mysqldump --databases db1 > db1.sql mysqldump --databases db2 > db2.sql ...
使用 DROP DATABASE
語句刪除數據庫。
關閉 MySQL Server ,設置 lower_case_table_names
以後重啓服務器。
從新加載數據庫,因爲修改了 lower_case_table_names
變量,每一個數據庫和表名在從新建立時都會轉換成小寫。
mysql < db1.sql mysql < db2.sql ...
若是標識符名的大寫形式在二進制規則排序後相等,則能夠認爲它們是重複的。這種狀況在遊標,條件,過程,函數,保存點,存儲例程的參數,存儲的程序局部變量和插件中適用。在列名,約束,數據庫,分區,預編譯語句<sup>③</sup>,表名,觸發器,用戶和用戶定義變量中是無效的<sup>④</sup>。
PREPARE
,猜想 JDBC 中的 PreparedStatement 對象就是來源於此,以後會挑時間查閱 MySQL 官方文檔學習。