我已经在PostgresQL之上构建了一个应用程序,该应用程序使用自定义序列。我认为我现在很好地理解序列:它们是非事务性的,currval仅在当前会话中定义,等等。但我不明白这一点:
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,得到了一个合理的数字,然后我们做了一个UPDATE来调用一个尝试在该序列上使用currval的触发器函数。 ..它失败了,声称currval没有定义。
请注意,这通常不会发生,但一旦开始发生,它就会始终如此(可能直到用户断开与DB的连接)。
这怎么可能?我能做些什么呢?
答案 0 :(得分:0)
您的UPDATE
声明显然会触发。导致此错误的最可能原因是触发器函数与定义序列的位置不同,并且序列的架构不在search_path
中。这为您提供了两种解决方案:
SET search_path TO ...
使序列的模式对触发器函数可见。请注意,这将使序列模式中的所有对象可见,这可能存在安全风险,具体取决于您的数据库设计。currval('my_schema.commit_id_seq')
。另一个可能的原因是应用程序端的连接池。 Log the "session ID" {实际会话的开始时间pid
%c
,log_line_prefix()
postgresql.conf
参数BEGIN ... COMMIT
。在PostgreSQL中,除非明确建立事务,否则每个命令都在其自己的事务中运行。连接池软件也可以在事务级别工作(即,您启动事务,然后您的连接将保持打开状态,直到您关闭它,在事务之外无法保证会话持久性)。如果是这种情况,您可以将整个命令集包装在nextval()
块中(您可能应该使用池化软件中的特定调用),或者更好的是,将代码更改为不依赖于之前的{{ 1}}来电。