1. <em id="vzzs9"></em>
      <tbody id="vzzs9"></tbody>

    2. <span id="vzzs9"></span>
      <progress id="vzzs9"></progress>
      首頁 運維干貨一條 update 語句引起的事故,這回讓開發長長記性??!

      一條 update 語句引起的事故,這回讓開發長長記性??!

      運維派隸屬馬哥教育旗下專業運維社區,是國內成立最早的IT運維技術社區,歡迎關注公眾號:yunweipai
      領取學習更多免費Linux云計算、Python、Docker、K8s教程關注公眾號:馬哥linux運維

      一條 update 語句引起的事故,這回讓開發長長記性??!插圖

      一、前言

      最近經常碰到開發誤刪除誤更新數據,這不,他們又給我找了個麻煩,我們來看下整個過程。

      二、過程

      由于開發需要在生產環節中修復數據,需要執行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進行了解析。

      一條 update 語句引起的事故,這回讓開發長長記性??!插圖1

      趕緊和開發確定了操作的時間點,生成flashback的SQL,進行了數據恢復,同時保留現場證據。

      然后對開發執行的SQL進行了check,發現了幾條很詭異的SQL:

      一條 update 語句引起的事故,這回讓開發長長記性??!插圖2

      這幾條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’的記錄也查找出來了,為什么呢?

      mysql [localhost] {msandbox} (test) > warnings
      Show warnings enabled.
      mysql [localhost] {msandbox} (test) > explain extended select id,str_col from tbl_name where str_col="xxx" = "yyy"\G
      *************************** 1. row ***************************
                 id: 1
        select_type: SIMPLE
              table: tbl_name
               type: index
      possible_keys: NULL
                key: idx_str
            key_len: 33
                ref: NULL
               rows: 4
           filtered: 100.00
              Extra: Using where; Using index
      1 row in set, 1 warning (0.00 sec)
      
      Note (Code 1003): /* select#1 */ select `test`.`tbl_name`.`id` AS `id`,`test`.`tbl_name`.`s
      

      這里他把where條件轉化成了

      ((`test`.`tbl_name`.`str_col` = 'xxx') = 'yyy')
      

      這個條件的首先判斷str_col 和’xxx’是否相等,如果相等,那么里面括號的值為1,如果不相等,就是0 然后0或者1再和和’yyy’進行判斷, 由于等號一邊是int,另外一邊是字符串,兩邊都轉化為float進行比較,可以看我之前的一篇文章MySQL中隱式轉換導致的查詢結果錯誤案例分析’yyy’轉化為浮點型為0,0和0比較恒等于1。

      mysql [localhost] {msandbox} (test) > select 'yyy'+0.0;
      +-----------+
      | 'yyy'+0.0 |
      +-----------+
      |         0 |
      +-----------+
      
      1 row in set, 1 warning (0.00 sec)
      
      mysql [localhost] {msandbox} (test) > select 0=0;
      +-----+
      | 0=0 |
      +-----+
      |   1 |
      +-----+
      1 row in set (0.00 sec)
      

      這樣導致結果恒成立,也就是select語句等價于以下SQL

      select id,str_col from tbl_name where 1=1;
      

      將查詢出所有的記錄。

      三、小結

      在寫SQL的過程中,一定要小心引號的位置是否正確,有時候引號位置錯誤,SQL依然是正常的,但是卻會導致執行結果全部錯誤。

      在執行前必須在測試環境執行測試,結合IDE的語法高亮發現相應的問題。

      (版權歸原作者所有,侵刪)

      本文鏈接:http://www.abandonstatusquo.com/39919.html

      網友評論comments

      發表評論

      您的電子郵箱地址不會被公開。

      暫無評論

      Copyright ? 2012-2022 YUNWEIPAI.COM - 運維派 京ICP備16064699號-6
      掃二維碼
      掃二維碼
      返回頂部
      久久久久亚洲国内精品|亚洲一区二区在线观看综合无码|欧洲一区无码精品色|97伊人久久超碰|一级a爱片国产亚洲精品