2015-10-19 76 views
2

我有一個基於PostgresQL構建的應用程序,該應用程序使用自定義序列。我想我明白序列現在很好:他們非事務,CURRVAL僅在當前會話中定義的,等等,但我不明白這一點:當我剛剛調用nextval時,pgsql序列如何定義?

2015-10-13 10:37:16 SQLSelect: SELECT nextval('commit_id_seq') 
2015-10-13 10:37:16 commit_id_seq: 57 
2015-10-13 10:37:16 SQLExecute: UPDATE bid SET is_archived=false,company_id=1436,contact_id=15529,...(etc)...,sharing_policy='' WHERE id = 56229 
2015-10-13 10:37:16 ERROR: ERROR: currval of sequence "commit_id_seq" is not yet defined in this session 
CONTEXT: SQL statement "INSERT INTO history (table_name, record_id, sec_user_id, created, action, notes, status, before, after, commit_id) 
     SELECT TG_TABLE_NAME, rec.id, (SELECT id FROM sec_user WHERE name = CURRENT_USER), now(), SUBSTR(TG_OP,1,1), note, stat, oldH, newH, currval('commit_id_seq')" 
PL/pgSQL function log_to_history() line 28 at SQL statement 
[3] 

我們會記錄每次調用數據庫,在SELECT nextval的情況下,我也記錄結果。以上是確切的調用,除了我修剪UPDATE語句(因爲原文很長)。

所以,你可以看到我們就叫 NEXTVAL在序列中,有一個合理的數目回來,然後我們做調用試圖在該序列使用CURRVAL觸發功能的更新......它失敗,聲稱currval沒有定義。

請注意,這通常不會發生,但一旦它開始發生,它會一直如此(也許直到用戶斷開數據庫)。

這怎麼可能?我能做些什麼呢?

+1

有趣。你是否使用任何中間件進行連接池或像'pgpool-II'或'pgBouncer'這樣的負載平衡?也許你的客戶端庫執行連接池?當你在單個事務中顯式執行nextval和update時,問題是否會消失? – Tometzky

+0

如果您記錄後端PID,也會很有幫助 - 在'log_line_prefix'配置選項中添加'%p'或在顯式日誌記錄中使用'pg_backend_pid()'。 – Tometzky

+0

我們不使用明確的交易。客戶端庫中的連接池是一種可能性。我會研究是否可以記錄後端PID。 –

回答

0

您的UPDATE聲明顯然會觸發一個觸發器。這種錯誤最可能的原因是觸發器函數與序列定義的位置不同,並且序列的架構不在search_path中。這給你兩個選擇來解決這個問題:

  1. 使用SET search_path TO ...使序列的模式對觸發函數可見。請注意,這將使序列模式中的所有對象可見,這可能會帶來安全風險,這取決於您的數據庫設計。
  2. 模式 - 在觸發函數中限定序列名稱:currval('my_schema.commit_id_seq')

另一個合理的原因是應用程序端的連接池。 Log the "session ID"(實際上只是當前會話的開始時間和pid),將%c添加到postgresql.conf中的log_line_prefix()參數中。在PostgreSQL中,除非明確建立事務,否則每個命令都在自己的事務中運行。連接池軟件也可以在事務級別工作(即,您啓動一​​個事務,然後您的連接將保持打開狀態,直到您關閉它爲止,而在事務之外沒有關於會話持久性的保證)。如果是這種情況,您可以將整套命令包裝在BEGIN ... COMMIT區塊中(您可能需要使用聯合軟件中的特定呼叫),或更好地更改代碼,以使其不依賴於以前的nextval()呼叫。

+0

這是一個有趣的想法,我花了一些時間來研究它。但\ dn恰恰顯示了1個模式(「公共」)。我們從未使用過多模式功能。此外,如果這是問題,我會期望它每次都會失敗,而不僅僅是我們實際看到的偶然失敗。 –

+0

增加了另一個可能的原因。 – Patrick

相關問題