一、前言
最近經常碰到開發誤刪除誤更新數據,這不,他們又給我找了個麻煩,我們來看下整個過程。
二、過程
由于開發需要在生產環節中修復數據,需要執行120條SQL語句,需要將數據進行更新
于是開發連上了生產數據庫,首先執行了第一條SQL
| update tablename set source_name = "bj1062-北京市朝陽區常營北辰福第"where source_name = "-北京市朝陽區常營北辰福第" |
我們仔細看了下,這個SQL,的確沒有什么問題,where條件也是正常的,大意就是將這個地址的前面加字符串bj1062,是真的沒有錯誤么?是的沒有錯誤。開發執行完成后,結果的確是符合預期。
然后開發執行了剩下的SQL,都是和上面的SQL一樣,將地址進行更新。執行完成后,開發懵逼了,發現source_name都變成了0,開發趕緊給我打電話說:
Harvey,我執行了update,where條件都是對的,set的值也是對的,但是set后的字段全部都變成了0,你趕緊幫我看看,看看能不能恢復數據。
我趕緊登上服務器,查看了這段時間的binlog,發現了大量的update tablename set source_name=0的語句,利用binlog2sql進行了解析,項目地址:binlog2sql

趕緊和開發確定了操作的時間點,生成flashback的SQL,進行了數據恢復,同時保留現場證據。
然后對開發執行的SQL進行了check,發現了幾條很詭異的SQL:

這幾條SQL的引號位置跑到了where 字段名字后面,簡化后的SQL變成了:
| update tbl_name set str_col="xxx" = "yyy" |
那么這個SQL在MySQL他是如何進行語義轉化的呢?
可能是下面這樣的么?
| update tbl_name set (str_col="xxx" )= "yyy" |
這樣就語法錯誤了,那么只會是下面這樣的形式,
| update tbl_name set str_col=("xxx" = "yyy") |
而
| select "xxx" = "yyy" |
的值是0,所以
| update tbl_name set str_col="xxx" = "yyy" |
等價于
| update tbl_name set str_col=0 |
所以就導致了source_name字段全部更新成了0.
我們再研究下select形式這種語句會怎么樣。
| mysql [localhost] {msandbox} (test) > select id,str_col from tbl_name where str_col="xxx" = "yyy";+----+---------+| id | str_col || 1 | aaa |+----+---------+ | 2 | aaa |+----+---------+| 3 | aaa || 4 | aaa | |
我們發現,這個SQL將str_col='aaa'
新聞熱點
疑難解答