一個空格引發的“慘案“

“案情”回顧(情景模擬):小張是一名軟件工程師,

工作兢兢業業、一絲不苟且精益求精,天性樂觀的他每天愉快地做著增刪改查的工作,對於這些看似簡單的CRUD,小張從來不會掉以輕心,他也篤定地堅信,自己向數據庫裡插入了什麼數據,就能按條件把這些數據查詢出來,畢竟,像MySQL這樣的數據庫,在全世界廣為流行,大行其道,不可能不嚴謹。

然而,意想不到的悲劇還是發生了。。。

小張做的項目與語言處理有點關係,他們把處理的結果也就是字符串保存到在數據庫裡面,後續需要按照條件把這些數據查詢出來,但需要對這些字符串做嚴格的區分,也就是說,如果查詢A字符串,不能把B字符串查詢出來,哪怕這兩個字符串只有一個空格的差異。對於這樣的需求,小張覺得太天經地義了,根本無需多言,像MySQL這樣的數據庫天生就是幹這樣的事,所以當時就自信滿滿地拍著胸脯保證一定如期開發完成。

隨著工作的推進,小張猛然發現MySQL對於字符串的處理貌似不那麼嚴謹,特別是對於空格字符,比如這兩個字符串:"Tom"和"Tom ",後面的字符串多了一個空格,然而,MySQL竟然把它們當成了相同的字符串。

我們來測試一下,看看具體的情況,先創建一個表:

<code>CREATE TABLE `white_space`(
`id` bigint(20)unsigned NOT AUTO_INCREMENT,
`name`varchar(128) NOT DEFAULT '',
PRIMARY KEY (`id`)
) ENGINE=InnoDBDEFAULT CHARSET=utf8/<code>

然後向表裡插入兩條數據:

<code>INSERT INTO white_space(name) VALUES('Tom');
INSERT INTO white_space(name) VALUES('Tom ');/<code>

注意,後面那條記錄在最後多了一個空格。假設我們需要查詢名字為Tom的記錄(沒有空格),SQL很簡單:

<code>SELECT * FROM white_space WHERE name = 'Tom';/<code>

然而,讓小張大跌眼鏡的是,上面的SQL竟然返回兩條數據,也就是說,本來查找"Tom"(沒有空格),卻把"Tom "(有空格)也查詢出來了:

一個空格引發的“慘案“

這也太不嚴謹了,空格也是字符啊,為什麼就生生的把它忽略了呢?這樣的話,就滿足不了項目的需求了,而且,小張還發現,不管後面有多少個空格,都會被忽略。我們再插入一條記錄,名字是"Tom ",後面一共有10個空格:

<code>INSERT INTO white_space(name) VALUES('Tom ');/<code>

再執行上面的查詢語句,這時仍然還是返回了三條記錄:

<code>SELECT * FROM white_space WHERE name = 'Tom';/<code>
一個空格引發的“慘案“

這簡直太不可理喻了!感覺MySQL在這裡完全無視空格的存在,但空格也是一個正正經經的字符啊,而且是一個非常常見的字符,咋就這麼沒有存在感呢。

當然,如果是前置空格,或者空格在中間是不會有這個問題的,比如數據庫裡保存的名字為" Tom"(最前面是一個空格),或者是"To m",再按"Tom"(沒有空格)去查詢的話,是找不到這條記錄的。

這就麻煩了,當初可是拍著胸脯保證可以如期完成的,現在碰到這樣的問題,小張可真是有點慌了神,不知道該如何來解決,而且這也是非常不可思議的事情,強悍如斯、威武如斯、名聲震天響的MySQL竟然如此不嚴謹。幸虧空格不會說話,要不然它還不得罵街啊,作為一個名正言順的字符,就這樣生生地被忽略了,這也太不尊重人了。

事已至此,小張只能去尋找問題的解決方法,抱怨是沒有用的,經過一番辛勤探索和研究,小張終於找到了辦法,也就是加上BINARY關鍵字,像下面這樣:

<code>SELECT * FROM white_space WHERE BINARY name = 'Tom';/<code>

這時候就會嚴格地進行匹配,只返回了一條記錄,如果要查詢包含空格的記錄,比如"Tom "(有空格),就會只返回有空格的這條記錄:

<code>SELECT * FROM white_space WHERE BINARY name = 'Tom ';/<code>

完美!項目就是需要這樣的效果,字符串要進行嚴格的匹配與區分,現在加上BINARY關鍵字就徹底地解決了這個問題,小張不禁有些沾沾自喜,他也覺得MySQL確實太強大了,不管什麼樣的問題貌似都有辦法解決,怪不得它會風靡全世界,成為了萬千企業的首選。

然而,小張還沒有高興沒多久,新的問題就又出現了。BINARY是MySQL獨有的關鍵字,Oracle數據庫並不認識什麼BINARY,而項目需要適配不同的數據庫,主要包括MySQL和Oracle。公司有一套ORM來做這樣的適配,開發人員只要按照標準來寫SQL就可以了,但是,如果在SQL語句中加上BINARY,切換到Oracle數據庫就會出錯,這可怎麼辦?!當然,也可以判斷數據庫的類型,如果是MySQL數據庫,就加上BINARY關鍵字,否則就不加(Oracle數據庫可以嚴格區分後置空格),但是,這樣的改動也太大了,因為MySQL中的語句都完全忽略了後置空格的存在,比如GROUP BY:

<code>SELECT name,COUNT(*) FROM white_space GROUP BY name/<code>

返回這樣的結果:

一個空格引發的“慘案“

也是完全忽略了後置空格,當然,加上BINARY也是可以解決問題的。

這樣看來,只要涉及到需要嚴格區分字符串的地方,都需要做這樣的改動,而這樣的字段還有好幾個,改動實在太大了!

事到如今,小張依然還沒有找到完善的解決方案,開發的工期也一拖再拖,可以說是一樁不折不扣的“慘案”了。

親愛的讀者朋友,你有什麼好的解決方案嗎?歡迎後臺留言討論。


分享到:


相關文章: