轉自:互聯(lián)網(wǎng)全棧架構
小張是一名軟件工程師,工作兢兢業(yè)業(yè)、一絲不茍且精益求精,天性樂觀的他每天愉快地做著增刪改查的工作,對于這些看似簡單的CRUD,小張從來不會掉以輕心,他也篤定地堅信,自己向數(shù)據(jù)庫里插入了什么數(shù)據(jù),就能按條件把這些數(shù)據(jù)查詢出來,畢竟,像MySQL這樣的數(shù)據(jù)庫,在全世界廣為流行,大行其道,不可能不嚴謹。
小張做的項目與語言處理有點關系,他們把處理的結果也就是字符串保存到在數(shù)據(jù)庫里面,后續(xù)需要按照條件把這些數(shù)據(jù)查詢出來,但需要對這些字符串做嚴格的區(qū)分,也就是說,如果查詢A字符串,不能把B字符串查詢出來,哪怕這兩個字符串只有一個空格的差異。對于這樣的需求,小張覺得太天經(jīng)地義了,根本無需多言,像MySQL這樣的數(shù)據(jù)庫天生就是干這樣的事,所以當時就自信滿滿地拍著胸脯保證一定如期開發(fā)完成。隨著工作的推進,小張猛然發(fā)現(xiàn)MySQL對于字符串的處理貌似不那么嚴謹,特別是對于空格字符,比如這兩個字符串:"Tom"和"Tom ",后面的字符串多了一個空格,然而,MySQL竟然把它們當成了相同的字符串。
我們來測試一下,看看具體的情況,先創(chuàng)建一個表:CREATE?TABLE?`white_space`(
`id`?bigint(20)unsigned?NOT?NULL?AUTO_INCREMENT,
`name`varchar(128)?NOT?NULL?DEFAULT?'',
PRIMARY?KEY?(`id`)
)?ENGINE=InnoDBDEFAULT?CHARSET=utf8
INSERT?INTO?white_space(name)?VALUES('Tom');
INSERT?INTO?white_space(name)?VALUES('Tom?');
注意,后面那條記錄在最后多了一個空格。假設我們需要查詢名字為Tom的記錄(沒有空格),SQL很簡單:SELECT?*?FROM?white_space?WHERE?name?=?'Tom';
?然而,讓小張大跌眼鏡的是,上面的SQL竟然返回兩條數(shù)據(jù),也就是說,本來查找"Tom"(沒有空格),卻把"Tom "(有空格)也查詢出來了:

這也太不嚴謹了,空格也是字符啊,為什么就生生的把它忽略了呢?這樣的話,就滿足不了項目的需求了,而且,小張還發(fā)現(xiàn),不管后面有多少個空格,都會被忽略。我們再插入一條記錄,名字是"Tom ?? ? ? ? ",后面一共有10個空格:INSERT?INTO?white_space(name)?VALUES('Tom??????????');
再執(zhí)行上面的查詢語句,這時仍然還是返回了三條記錄:SELECT?*?FROM?white_space?WHERE?name?=?'Tom';
這簡直太不可理喻了!感覺MySQL在這里完全無視空格的存在,但空格也是一個正正經(jīng)經(jīng)的字符啊,而且是一個非常常見的字符,咋就這么沒有存在感呢。當然,如果是前置空格,或者空格在中間是不會有這個問題的,比如數(shù)據(jù)庫里保存的名字為" Tom"(最前面是一個空格),或者是"To m",再按"Tom"(沒有空格)去查詢的話,是找不到這條記錄的。這就麻煩了,當初可是拍著胸脯保證可以如期完成的,現(xiàn)在碰到這樣的問題,小張可真是有點慌了神,不知道該如何來解決,而且這也是非常不可思議的事情,強悍如斯、威武如斯、名聲震天響的MySQL竟然如此不嚴謹。幸虧空格不會說話,要不然它還不得罵街啊,作為一個名正言順的字符,就這樣生生地被忽略了,這也太不尊重人了。事已至此,小張只能去尋找問題的解決方法,抱怨是沒有用的,經(jīng)過一番辛勤探索和研究,小張終于找到了辦法,也就是加上BINARY關鍵字,像下面這樣:SELECT?*?FROM?white_space?WHERE?BINARY?name?=?'Tom';
這時候就會嚴格地進行匹配,只返回了一條記錄,如果要查詢包含空格的記錄,比如"Tom "(有空格),就會只返回有空格的這條記錄:SELECT?*?FROM?white_space?WHERE?BINARY?name?=?'Tom?';
完美!項目就是需要這樣的效果,字符串要進行嚴格的匹配與區(qū)分,現(xiàn)在加上BINARY關鍵字就徹底地解決了這個問題,小張不禁有些沾沾自喜,他也覺得MySQL確實太強大了,不管什么樣的問題貌似都有辦法解決,怪不得它會風靡全世界,成為了萬千企業(yè)的首選。然而,小張還沒有高興沒多久,新的問題就又出現(xiàn)了。BINARY是MySQL獨有的關鍵字,Oracle數(shù)據(jù)庫并不認識什么BINARY,而項目需要適配不同的數(shù)據(jù)庫,主要包括MySQL和Oracle。公司有一套ORM來做這樣的適配,開發(fā)人員只要按照標準來寫SQL就可以了,但是,如果在SQL語句中加上BINARY,切換到Oracle數(shù)據(jù)庫就會出錯,這可怎么辦?!當然,也可以判斷數(shù)據(jù)庫的類型,如果是MySQL數(shù)據(jù)庫,就加上BINARY關鍵字,否則就不加(Oracle數(shù)據(jù)庫可以嚴格區(qū)分后置空格),但是,這樣的改動也太大了,因為MySQL中的語句都完全忽略了后置空格的存在,比如GROUP BY:SELECT?name,COUNT(*)?FROM?white_space?GROUP?BY?name

也是完全忽略了后置空格,當然,加上BINARY也是可以解決問題的。
這樣看來,只要涉及到需要嚴格區(qū)分字符串的地方,都需要做這樣的改動,而這樣的字段還有好幾個,改動實在太大了!事到如今,小張依然還沒有找到完善的解決方案,開發(fā)的工期也一拖再拖,可以說是一樁不折不扣的“慘案”了。-End-
更多精彩:
SpringSecurity + JWT 權限系統(tǒng)
非常強悍的 RabbitMQ 總結,寫得真好!
這個IDEA插件,專門解決Maven依賴沖突
RabbitMQ+WebSocket實現(xiàn)大屏幕消息推送
這7 款 MySQL 客戶端工具,用了都說好!
Spring 和 Spring Boot 最核心的 3 大區(qū)別
明天見(??ω??)??