PostgreSQL的问题:’now’不断返回相同的旧值

我有一个旧的Web应用程序,相关的当前堆栈是: Java 8,Tomcat 7,Apache Commons DBCP 2.1,Spring 2.5(用于事务),iBatis,Postgresql 9.2和postgresql-9.4.1208.jar

部分代码在事件表中插入新记录,其中字段begin_date(带时区的时间戳(3))是创建时间戳,现在填充:

insert into incidents
    (....,begin_date,)
    values
    (...,'Now' ....)

所有这些都是通过iBatis执行的,通过Spring以编程方式管理的事务,通过DBCP池获取的连接. webapp(实际上是一对,客户端和后台,共享大部分代码和jar)多年来一直在工作.

最近,也许在一些库更新和重组之后(似乎没什么重要的),我一直在经历(间歇性,难以重现)一些令人讨厌的问题:现在似乎冻结了,它开始返回相同的“旧”值.然后,许多记录显示具有相同的创建时间戳,小时或几天前:

db=# select 'Now'::timestamptz;
        timestamp
-------------------------
 2016-06-10 21:59:03.637+00

db=#  select rid,begin_date from incidents order by rid desc limit 6;
  rid  |         begin_date
-------+----------------------------
 85059 | 2016-06-08 00:11:06.503+00
 85058 | 2016-06-08 00:11:06.503+00
 85057 | 2016-06-08 00:11:06.503+00
 85056 | 2016-06-08 00:11:06.503+00
 85055 | 2016-06-08 00:11:06.503+00
 85054 | 2016-06-08 00:11:06.503+00

(以上所有记录实际上是在2016-06-10 21:50之前的几分钟创建的)

怎么会发生这种情况?它可能是与事务和/或连接池有关的一些问题,但我无法弄清楚是什么.
我知道’now()‘是transaction_timestamp()的别名,它返回事务开始时的时间.这表明交易没有正确关闭,上面的记录插入(无​​意中)写在一个长期交易中.但这对我来说相当不可思议.

首先,我可以插入一条新记录(通过webapp),并使用psql控制台,我看到它是用相同的begin_date编写的(如果事务是uncommited,我不应该看到新记录,我有认值序列化水平).

此外,pg_stat_activity视图仅显示空闲连接.

任何线索?

解决方法

“现在”有常量(特殊时间戳值).
现在有了函数().

你自由地混合它们这一事实表明你并没有意识到最重要的区别. The manual:

Special Values

Postgresql supports several special date/time input values for
convenience,as shown in Table 8-13. The values infinity and -infinity
are specially represented inside the system and will be displayed
unchanged; but the others are simply notational shorthands that will
be converted to ordinary date/time values when read. (In particular,
Now and related strings are converted to a specific time value as soon
as they are read.)
All of these values need to be enclosed in single
quotes when used as constants in sql commands.

大胆强调我的.

并且(就像你已经提到的那样),但引用了the manual

Now() is a Traditional Postgresql equivalent to transaction_timestamp().

和:

transaction_timestamp() is equivalent to CURRENT_TIMESTAMP

还有更多,阅读整章.

现在(没有双关语),因为您使用特殊值而不是函数,所以您使用预准备语句获得了不同的(意外的)行为.

考虑这个演示:

test=# BEGIN;
BEGIN
test=# PREPARE foo AS
test-# SELECT timestamptz 'Now' AS Now_constant,Now() AS Now_function;
PREPARE
test=# EXECUTE foo;
         Now_constant          |         Now_function
-------------------------------+-------------------------------
 2016-06-11 03:09:05.622783+02 | 2016-06-11 03:09:05.622783+02 -- identical
(1 row)

test=# commit;
COMMIT
test=# EXECUTE foo;
         Now_constant          |         Now_function
-------------------------------+------------------------------
 2016-06-11 03:09:05.622783+02 | 2016-06-11 03:10:00.92488+02  -- different!
(1 row)

当您在同一个事务中运行时,’Now’和Now()会生成相同的值.但是,准备好的语句旨在持续会话期间(可能跨越许多事务).下次执行预准备语句时,您将看到不同之处.

换句话说:’Now’实现“早期绑定”,而Now()实现“后期绑定”.

您可能已经引入了预准备语句和/或连接池(可以在较长时间内保留准备好的语句) – 这两者通常都是好主意.但是你的INSERT中隐藏的问题现在开始了.

您看到的“空闲连接”表示同样多:连接保持打开状态,保留准备好的语句.

简而言之:立即使用().

或者,将列认值begin_date设置为Now()(不是’Now’!),并且不要在INSERT中提及该列.您的“创建时间戳”会自动保存.

相关文章

项目需要,有个数据需要导入,拿到手一开始以为是mysql,结果...
本文小编为大家详细介绍“怎么查看PostgreSQL数据库中所有表...
错误现象问题原因这是在远程连接时pg_hba.conf文件没有配置正...
因本地资源有限,在公共测试环境搭建了PGsql环境,从数据库本...
wamp 环境 这个提示就是说你的版本低于10了。 先打印ph...
psycopg2.OperationalError: SSL SYSCALL error: EOF detect...