加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-13 15:55:19 所属栏目:百科 来源:网络整理
导读:我有一个旧的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))是创建时间戳,现在填充
我有一个旧的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中提及该列.您的“创建时间戳”会自动保存.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读