由 select * 引发的“惨案”
?
? ? ??今天凌晨做發布, 要合并多個分數據庫的表數據到主數據庫中, 有 30+ 分數據庫。 前面都比較順利, 在臨近結束時,突然發現一個字段的值插入錯誤。 有一個表 T,字段分別為 (f1, f2, f3, gmt_create, gmt_modify, name) 。 假設分數據庫為 a1, a2, ..., a30 , 主數據庫為 A 。 合并的邏輯是: 從 a1, a2, ..., a30 取出對應的字段, 依次插入到 主數據庫中。
aRet = adb.query("select * from T")allTuples = []for (f1, f2, f3, gmt_create , gmt_modify, name) in aRet:allTuples.append((f1, f2, f3, gmt_create, gmt_modify, name))Adb.executeMany("insert into T(f1, f2, f3, gmt_create, gmt_modify, name) values(%s, %s, %s, %s, %s, %s)", allTuples)log.info(allTuples)Adb.commit()
? ? ? NOTE: ?這里會將 allTuples 分成 1000 個元組一片進行提交執行。 不過不影響此處的理解。
? ? ? 那么, 這會有什么問題呢? 初看上去似乎沒什么, 但是“慘案” 就這樣發生了。?
? ? ? 有一個集群 ai 的表 T 的字段順序跟其他集群的略有不同。其表字段順序是 (f1, f2, f3, name , gmt_create, gmt_modify) 。 這樣從 ai 取出的數據 (f1, f2, f3, name, gmt_create, gmt_modify) 將插入到 A 的 (f1, f2, f3, gmt_create, gmt_modify, name) , 也就是說, a1.name 插入到 A.gmt_create, ?a1.gmt_create 插入到 A.gmt_modify, ?a1.gmt_modify 插入了 A.name ?, ? 由于 gmt_create , ?gmt_modify, name 均為字符串, 因此沒有報錯。 驗證的時候, 由于另外一個地方因其他原因報了大量錯誤,掩蓋了這個問題。
? ? ? 解決的辦法很簡單: 將 "select * from T" 改為 "select?f1, f2, f3, gmt_create , gmt_modify, name ?from T"
? ? ? 教訓: 在做“逐字段取出-插入” 的數據庫操作時, 切忌使用 “select * ”
?
? ? ? ?發現數據插入錯誤之后, 馬上進行清空和重新執行。 這時, 更糟糕的事情發生了。 由于清空操作要考慮將對 T.A 的新改動(考慮到發布過程中會有外部調用修改T.A的數據)同步到 T.ai 。 而上述已經對 T.A 進行了大量改動, ?因此會以 T.A 的數據為準, 對 T.ai 的相應記錄進行回寫, 結果將 ai 的原數據覆蓋了, 且沒有預先做表備份。 ai 的數據就這樣丟失了! ?
? ? ? ?教訓: ?合并過程中, 最好不要回寫源數據庫, 降低復雜性; 如果一定要回寫源數據庫, 要單獨做一個腳本, 取名更明顯, 且要做表備份操作。 ?
? ? ?
? ? ? ?現在必須馬上恢復數據! 當時差點忘了, 由于?db.executeMany 接口沒辦法獲取到直接執行的SQL, 因此昨天早上思慮再三,新添了一行代碼使用了 log.info(allTuples) , 記錄下了所要插入的源數據。 萬一出問題, 避免從 DB 中取執行SQL的麻煩。 ?不過, 由于偷了一點懶, 打印出的 allTuples 的格式相當難以解析, 費了不少勁才將 <primarykey, name> 的關系取出來, 重新做了訂正。 昨天早上的那行代碼成了今天早上的救命稻草之一。
? ? ? 教訓: ?對數據庫的insert, update, delete 操作一定要加日志。 如果數據庫接口不方便直接打印SQL的日志, 就要單獨打印出源數據以備后用。 此外, 最好不要偷懶, 因為每一點偷懶都會對后面某個時候造成障礙, 而稍微做的便利一點, 就會對后續產生有益的用處。 這都是活生生的教訓。?
?
轉載于:https://www.cnblogs.com/lovesqcc/p/4195432.html
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的由 select * 引发的“惨案”的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 深入浅出设计模式——组合模式(Compo
- 下一篇: 初学ctypes:打开进程并返回相关信息