1. 程式人生 > >Psotgresql如何記錄一次事務中每個操作的時間

Psotgresql如何記錄一次事務中每個操作的時間

實際業務需求是這樣的:在一些業務中常用的基本表修改時沒有履歷記錄,查問題時比較麻煩。

在Table上建立rule / 觸發器可以解決此問題,在實際操作中會有一個問題

以 m_ope_d為例:

--記錄m_ope_d   insert履歷
create rule rule_insert_m_ope_d as on
insert to m_ope_d do also insert into m_ope_d_log( oprtype, oprtime,ope_key, unq_seq_id, etl_timestamp, etl_event_node, etl_event_name, etl_evt_seq_id, ope_id, ope_ver, ope_dsc, shop_key_fk, shop_id, proc_id, eqpt_gp_key_fk, eqpt_gp_id, eqpt_run_mode, ope_seq_no, pep_lvl, up_load_id, dn_load_id, wk_cent_id, wk_cent_dsc, evt_cate, evt_user, evt_timestamp, evt_note, ope_type, mes_ope_flg, ope_proc_type, ope_def_format, ext_dept, ext_type, ext_sub_dept, valid_flg, group_name )
values('insert',current_timestamp(6), new.ope_key, new.unq_seq_id, new.etl_timestamp, new.etl_event_node, new.etl_event_name, new.etl_evt_seq_id, new.ope_id, new.ope_ver, new.ope_dsc, new.shop_key_fk, new.shop_id, new.proc_id, new.eqpt_gp_key_fk, new.eqpt_gp_id, new.eqpt_run_mode, new.ope_seq_no, new.pep_lvl, new.up_load_id, new.dn_load_id, new.wk_cent_id, new.wk_cent_dsc, new.evt_cate, new.evt_user, new.evt_timestamp, new.evt_note, new.ope_type, new.mes_ope_flg, new.ope_proc_type, new.ope_def_format, new.ext_dept, new.ext_type, new.ext_sub_dept, new.valid_flg, new.group_name )


--記錄m_ope_d   update履歷

create rule rule_update_m_ope_d as on
update to m_ope_d do also( insert into m_ope_d_log( oprtype, oprtime, ope_key, unq_seq_id, etl_timestamp, etl_event_node, etl_event_name, etl_evt_seq_id, ope_id, ope_ver, ope_dsc, shop_key_fk, shop_id, proc_id, eqpt_gp_key_fk, eqpt_gp_id, eqpt_run_mode, ope_seq_no, pep_lvl, up_load_id, dn_load_id, wk_cent_id, wk_cent_dsc, evt_cate, evt_user, evt_timestamp, evt_note, ope_type, mes_ope_flg, ope_proc_type, ope_def_format, ext_dept, ext_type, ext_sub_dept, valid_flg, group_name )
values( 'delete', clock_timestamp(), old.ope_key, old.unq_seq_id, old.etl_timestamp, old.etl_event_node, old.etl_event_name, old.etl_evt_seq_id, old.ope_id, old.ope_ver, old.ope_dsc, old.shop_key_fk, old.shop_id, old.proc_id, old.eqpt_gp_key_fk, old.eqpt_gp_id, old.eqpt_run_mode, old.ope_seq_no, old.pep_lvl, old.up_load_id, old.dn_load_id, old.wk_cent_id, old.wk_cent_dsc, old.evt_cate, old.evt_user, old.evt_timestamp, old.evt_note, old.ope_type, old.mes_ope_flg, old.ope_proc_type, old.ope_def_format, old.ext_dept, old.ext_type, old.ext_sub_dept, old.valid_flg, old.group_name );

insert into m_ope_d_log( oprtype, oprtime, ope_key, unq_seq_id, etl_timestamp, etl_event_node, etl_event_name, etl_evt_seq_id, ope_id, ope_ver, ope_dsc, shop_key_fk, shop_id, proc_id, eqpt_gp_key_fk, eqpt_gp_id, eqpt_run_mode, ope_seq_no, pep_lvl, up_load_id, dn_load_id, wk_cent_id, wk_cent_dsc, evt_cate, evt_user, evt_timestamp, evt_note, ope_type, mes_ope_flg, ope_proc_type, ope_def_format, ext_dept, ext_type, ext_sub_dept, valid_flg, group_name )
values( 'insert', clock_timestamp(), new.ope_key, new.unq_seq_id, new.etl_timestamp, new.etl_event_node, new.etl_event_name, new.etl_evt_seq_id, new.ope_id, new.ope_ver, new.ope_dsc, new.shop_key_fk, new.shop_id, new.proc_id, new.eqpt_gp_key_fk, new.eqpt_gp_id, new.eqpt_run_mode, new.ope_seq_no, new.pep_lvl, new.up_load_id, new.dn_load_id, new.wk_cent_id, new.wk_cent_dsc, new.evt_cate, new.evt_user, new.evt_timestamp, new.evt_note, new.ope_type, new.mes_ope_flg, new.ope_proc_type, new.ope_def_format, new.ext_dept, new.ext_type, new.ext_sub_dept, new.valid_flg, new.group_name ))



--記錄m_ope_d   delete履歷

create rule rule_delete_m_ope_d as on
delete to m_ope_d do also insert into m_ope_d_log( oprtype, oprtime, ope_key, unq_seq_id, etl_timestamp, etl_event_node, etl_event_name, etl_evt_seq_id, ope_id, ope_ver, ope_dsc, shop_key_fk, shop_id, proc_id, eqpt_gp_key_fk, eqpt_gp_id, eqpt_run_mode, ope_seq_no, pep_lvl, up_load_id, dn_load_id, wk_cent_id, wk_cent_dsc, evt_cate, evt_user, evt_timestamp, evt_note, ope_type, mes_ope_flg, ope_proc_type, ope_def_format, ext_dept, ext_type, ext_sub_dept, valid_flg, group_name )
values( 'delete', current_timestamp(6), old.ope_key, old.unq_seq_id, old.etl_timestamp, old.etl_event_node, old.etl_event_name, old.etl_evt_seq_id, old.ope_id, old.ope_ver, old.ope_dsc, old.shop_key_fk, old.shop_id, old.proc_id, old.eqpt_gp_key_fk, old.eqpt_gp_id, old.eqpt_run_mode, old.ope_seq_no, old.pep_lvl, old.up_load_id, old.dn_load_id, old.wk_cent_id, old.wk_cent_dsc, old.evt_cate, old.evt_user, old.evt_timestamp, old.evt_note, old.ope_type, old.mes_ope_flg, old.ope_proc_type, old.ope_def_format, old.ext_dept, old.ext_type, old.ext_sub_dept, old.valid_flg, old.group_name )

以上,在為 m_ope_d建立update rule。在一次事務中,先delete 再 insert。如果oprtime 用now(),那麼delete 和insert的時間是一樣的,原因是:因為now()是按照當前事務的開始時刻返回結果的,所以他們的值在事務執行的整個期間內都不會再變。Postgresql這樣的做的目的是為了允許一個事務再 “當前時間”上有連貫的概念,這樣同一個事務裡的多個修改就可以保持同樣的時間戳了。 事實上,同一次事務中我希望看到的是這兩個時間應該是不一樣的。因此用clock_timestamp()函式。它的返回值會在事務中隨時間的前進而變化

有圖有真相:

還有如下函式有這樣的功能:

statement_timestamp();

timeofday().

像now()、current_timestamp和transcation_timestamp()函式都是等效的。

此外在使用timestamp型別的時候會有一些引數:

timestamp [(precision)] [without time zone]
此處需要注意的mysql的時間型別只能精確到s。timestamp接受一個可選精度的引數,P以指明秒域中小數部分的位數。
timestamp是以雙精度浮點數儲存的,timestamp是以2000-01-01午夜之前或之後的秒數儲存的,可以想象,在2000-01-01附近幾年的日期精度可以達到微妙的,在更遠的一些日子精度可能不能到達微妙,但是到達毫秒是沒有問題的。
timestamp without time zone 會將資料庫儲存的時間當做北京時間而非UTC時間,與資料庫時區沒有關係。
寫入DB的時間實際為北京時間,pg庫恰好是當做北京時間讀取,所以時間戳就不會出問題了。

假如應用部署在不同的地域,使用timestamp without time zone儲存timestamp這樣的設計簡直是災難

oprtime timestamp(6) without time zone NOT NULL,