2017-08-09 118 views
2

當某個字段發生更改時,我需要創建錶行的更改歷史記錄。所以我想要做的是在表更新上創建一個觸發器。當字段txta發生變化時,我希望整行被複制到debug,這是msser_210的一個克隆版本,最後添加了datetime的列,而沒有數據。我想在更改上添加NOW(),這樣我就可以獲得時間戳。這是我曾嘗試遠:如何爲表創建更改日誌?

DELIMITER $$ 
CREATE TRIGGER history_trigger 
BEFORE UPDATE ON msser_210 
    FOR EACH ROW 
     BEGIN 
     IF OLD.txta != NEW.txta 
     THEN 
      INSERT INTO `debug_history` (`idpm`,`posn`,`prnb`,`doid`,`ofcr`,`pidm`,`hitm`,`sitm`,`item`,`dsca`,`igid`,`kitm`,`leng`,`widt`,`hght`,`thik`,`radi`,`quas`,`wght`,`effc`,`colr`,`bdat`,`edat`,`back`,`cuid`,`intb`,`aggr`,`unqu`,`oqua`,`unsq`,`stoc`,`allo`,`hall`,`tqan`,`bqan`,`pkey`,`pric`,`cvqs`,`unsp`,`disc`,`dart`,`ksid`,`anhg`,`txta`,`txti`,`mndn`, `changedate`) VALUES (OLD.idpm,OLD.posn,OLD.prnb,OLD.doid,OLD.ofcr,OLD.pidm,OLD.hitm,OLD.sitm,OLD.item,OLD.dsca,OLD.igid,OLD.kitm,OLD.leng,OLD.widt,OLD.hght,OLD.thik,OLD.radi,OLD.quas,OLD.wght,OLD.effc,OLD.colr,OLD.bdat,OLD.edat,OLD.back,OLD.cuid,OLD.intb,OLD.aggr,OLD.unqu,OLD.oqua,OLD.unsq,OLD.stoc,OLD.allo,OLD.hall,OLD.tqan,OLD.bqan,OLD.pkey,OLD.pric,OLD.cvqs,OLD.unsp,OLD.disc,OLD.dart,OLD.ksid,OLD.anhg,OLD.txta,OLD.txti, OLD.mndn, NOW()); 
    END IF; 
END; 
$$ 

爲什麼我要做到這一點是因爲我們有(可能)與寫入相同的文本字符串到數據庫中的每一個領域,而是一個bug PHP腳本我們不知道什麼時候或爲什麼它不會發生它的腳本。有沒有更優雅的解決方案?

更新:我發現選項「修訂」在phpMyAdmin,但顯然它不會跟蹤我們的節目的PHP發行UPDATE查詢,從PHP的DROPCREATE TABLE語句雖然跟蹤。如果我通過phpMyAdmin發出UPDATE,它會被跟蹤。長話短說,我回到原來的計劃中。

UPDATE2:找到了答案了自己

回答

0

debug_history是通過pypMyAdmin從原始表克隆的。它手動添加了附加的更改列。

ALTER TABLE debug_history ADD COLUMN changedate DATETIME DEFAULT NULL; 

我決定,因爲沒有其他辦法,我必須自己輸入所有名稱。因爲我很懶,所以我得到了一個最近的SQL轉儲,從用來重建msser_210的文件中複製了INSERT INTO-語句並更改了這些值。

我添加了一個帶有自動增量行的額外行,放棄了主鍵並將新的主鍵設置爲新行。

ALTER TABLE debug_history DROP PRIMARY KEY; 
ALTER TABLE debug_history ADD COLUMN changenumber INT NOT NULL PRIMARY KEY AUTO_INCREMENT; 

我現在有一個工作的changelog,引發了關於在txta場變化(請參閱與原來的格式觸發的問題)。我將debug_history中的txta列更名爲txta_old,並創建了一個新列txta_new

ALTER TABLE debug_history CHANGE txta txta_old TEXT NOT NULL $$ 
ALTER TABLE debug_history ADD COLUMN txta_new TEXT NOT NULL AFTER txta_old $$ 

後來我不得不修改觸發器,因爲我不得不手動複製所有的名字..

DROP TRIGGER history_trigger 
DELIMITER $$ 
CREATE TRIGGER history_trigger 
BEFORE UPDATE ON msser_210 
    FOR EACH ROW 
     BEGIN 
     IF OLD.txta != NEW.txta 
     THEN 
      INSERT INTO `debug_history` (`idpm`,`posn`,`prnb`,`doid`,`ofcr`,`pidm`,`hitm`,`sitm`,`item`,`dsca`,`igid`,`kitm`,`leng`,`widt`,`hght`,`thik`,`radi`,`quas`,`wght`,`effc`,`colr`,`bdat`,`edat`,`back`,`cuid`,`intb`,`aggr`,`unqu`,`oqua`,`unsq`,`stoc`,`allo`,`hall`,`tqan`,`bqan`,`pkey`,`pric`,`cvqs`,`unsp`,`disc`,`dart`,`ksid`,`anhg`,`txta_old`,`txta_new`,`txti`,`mndn`, `changedate`) VALUES (OLD.idpm,OLD.posn,OLD.prnb,OLD.doid,OLD.ofcr,OLD.pidm,OLD.hitm,OLD.sitm,OLD.item,OLD.dsca,OLD.igid,OLD.kitm,OLD.leng,OLD.widt,OLD.hght,OLD.thik,OLD.radi,OLD.quas,OLD.wght,OLD.effc,OLD.colr,OLD.bdat,OLD.edat,OLD.back,OLD.cuid,OLD.intb,OLD.aggr,OLD.unqu,OLD.oqua,OLD.unsq,OLD.stoc,OLD.allo,OLD.hall,OLD.tqan,OLD.bqan,OLD.pkey,OLD.pric,OLD.cvqs,OLD.unsp,OLD.disc,OLD.dart,OLD.ksid,OLD.anhg,OLD.txta,NEW.txta,OLD.txti, OLD.mndn, NOW()); 
     END IF; 
    END; 
$$ 
1

更新:依照OP的評論,顯然上下文是非常具體的。無法訪問(或反饋和指導開發團隊)代碼的能力的基礎結構團隊需要一種機制,通過該機制記錄生產數據庫上的表更改。

警告有關使用觸發器

觸發器可能會非常棘手的調試,這不僅是因爲他們是透明的,它是一個新的人從來沒有明顯的看你的代碼,觸發被執行後面的一些動作場景。 (我根據經驗說話)。它們也可能導致replicated,多主站和羣集安裝中的問題。 (同樣,我是從經驗講的。)另外,如果由於某種不相關的原因而失敗(例如,他們寫入的表被破壞),整個事務可能會失敗(InnoDB) - 這可能不是您想要的。 (尤其是非必要的「調試」功能。)

否則,觸發器是非常有效的工具。 而在您的具體情況下,可能是您可以獲得的最佳選擇。

有提供給您多種其它選項,其中有兩個我要強調:

存儲過程作爲接入層到數據

如果你非常以數據爲中心,你已經有了數據庫中的業務邏輯 - (一個激烈爭論的話題,我不是在爭論你應該或不應該在數據庫中有業務邏輯),那麼通過存儲過程讀取和寫入數據庫具有明顯的優勢。

不限事務捆綁邏輯可以被插入,使得事務不安全呼叫者(PHP,作爲一個常見的例子)只需要調用1個查詢(call sp_insert_tablename(123, 'abc'))和事務安全可由強制執行這些存儲的過程數據庫。

可以將臨時調試邏輯添加到這些存儲過程中,並通過設置表,會話變量,最終參數中的標誌來啓用/禁用臨時調試邏輯,無論您希望如何。

數據抽象層/庫

類似的原理。爲你的客戶找到一個數據抽象層(假設你有權改變它的內部)。對於PHP或.NET Web應用程序,有幾種流行的選擇,所有這些選項都允許您覆蓋(通過代碼繼承擴展)保存/刪除操作以執行所需的任何其他操作 - 與存儲過程完全相同(但與邏輯在客戶端維護在模型中)。

如果你想有一個具體的例子,你需要給我們什麼堆/語言/框架()你正在使用

與這兩個選項的詳細信息,請務必妥善處理錯誤情況。

+1

TBH程序是一個失敗的事業,我不是它的開發者,我不能代碼PHP。我是服務器SysAdmin,我被告知將所有寫入給定數據庫的日誌都記錄下來,所以開發人員可以調試(甚至沒有單元測試等),這樣很好,但幾乎沒有,我真的可以做到這一點 – siryx

+0

這絕對沒問題。那麼我會建議我的答案仍然回答你的問題 - 「否則,觸發器是一個完全有效的工具。」堅持你提出的解決方案,那會很好。我與觸發器的經驗是由於你的情況完全相同 - 把他們放在那裏的人被迫去做。作爲更廣泛的話題的一部分,如果我處於你的位置,我會舉手(你是否有正式的基礎設施流程來接口開發人員,比如devops?),並說:「我被迫做這個,沒問題,但它會咬我們,我想要記錄下來「。 – wally

+0

我嘗試過了,但新表中的列數量不同,因爲我爲changedate添加了一列,並且想要將其設置爲 – siryx