1、生產bug
這是一個A系統從B系統同步項目信息的job。
2、排查
後臺報錯:
java.sql.SQLException: ORA-01795: maximum number of expressions in a list is 1000
原因:in裏面最多1000個值,如果in的括號裏面超過了1000個值,就會報這個錯誤。
經查,sqlMapping裏的sql確實是使用了 IN (不推薦在sql裏使用in,沒辦法,這是前人寫得)
那麼爲什麼會一次性過來超過1000條數據呢?
RPC監控平臺上,接口過來5019條數據。
同步的原理的是根據版本號:syncVersion
經查本系統A最大版本號爲:1563874473
而另一個系統B中比A的最大版本號大的數據有5019條
爲什麼突然有這麼多條數據呢?(正常情況下,一次job不可能有這麼多條數據)
經詢問,B系統的人,直接在數據庫執行過sql,根據時間點,發現就是B系統的人執行過sql之後,導致了A系統的job報錯。
經排查,發現B系統的sql改變了5018條數據,然後這5018條數據的版本號全部變爲相同的了,(這其中還有個同步表_sync-table,此處忽略),加上, 這又是爲什麼呢?
3、原來,是因爲觸發器的存在
之所以想到是觸發器的存在,是因爲在前段時間,另一個項目拆庫拆表的時候,搞過觸發器問題
注意到觸發器中,設定sync_version是取的當前時間,now(),mysql中的now(),只能精確到秒,當使用一條sql同時執行五千條數據時,是在幾百ms內執行完,所以這就是爲什麼上文中,這五千多條數據的版本號相同的原因。
4、解決問題
把A系統中的最大版本號更新爲合適的值(小於B系統的版本號的新增數據的最大值),再次執行job,成功。
5、聊聊 觸發器
——什麼是觸發器?
觸發器是一種特殊類型的存儲過程,它由事件觸發,而不是程序調用或手工啓動。
當數據庫有特殊的操作時,對這些操作由數據庫中的事件來觸發,自動完成這些SQL語句。
——觸發器與存儲過程的區別?
——觸發器的作用:
(1) 增加安全性
(2) 利用觸發器記錄所進行的修改以及相關信息,跟蹤用戶對數據庫的操作,實現審計。
(3) 維護哪些通過創建表時的聲明約束不可能實現的複雜的完整性約束以及對數據庫中特定事件進行監控與響應。
(4) 實現複雜的非標準的數據庫相關完整性規則、同步實時地複製表中的數據
(5) 觸發器是自動的,它們在對錶的數據做了任何修改之後就會被激活。 例如,可以自動計算數據值,如果數據的值達到了一定的要求,則進行特定的處理。 以某企業財務管理爲例,如果企業的資金鍊出現短缺,並且達到某種程度時,則發送警告信息。
——觸發器相關sql
(1)創建
創建有一條執行語句的觸發器:
create trigger trigger_name
before|after trigger_event
on table_name for each row trigger_stmt
創建包含多條執行語句的觸發器
create trigger trigger_name
before|after trigger_event
on table_name for each row
begin
trigger_stmt
end
(2)查看: show triggers
(3)刪除: drop trigger trigger_name
——根據SQL語句的不同,觸發器可分爲兩類:DML觸發器、DLL觸發器
DML觸發器是當數據庫服務器發生數據操作語言事件時執行的存儲過程,有After和Instead of兩種觸發器。After觸發器是當數據被激活觸發是在記錄該表之後進行的一種觸發器。 Instead of觸發器是在記錄變更之前,去執行觸發器本身所定義的操作,而不是執行原來SQL語句裏的操作。
DLL觸發器是在響應數據定義語言事件時執行的存儲過程。
——事前觸發、事後觸發的區別? 語句級觸發、行級觸發的區別?
事前觸發發生在事件發生之前驗證一些條件或進行有一些準備工作;
事後觸發發生在事件發生之後,做收尾工作,保證事務的完整性。 而事前觸發可以獲得之前和新的字段值。
語句級觸發可以在語句執行之前或之後執行,
行級觸發在觸發器所影響的每一行觸發一次。
6、最後,給點建議:
小心觸發器;
儘量少直接用sql操作生產數據庫;
遇到生產bug,解決問題的思路很重要;
技術很重要,態度更重要