2015-10-19 77 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

相关问题