gpt4 book ai didi

postgresql - PostgreSQL : 'now' keeps returning same old value 问题

转载 作者:行者123 更新时间:2023-11-29 11:35:03 25 4
gpt4 key购买 nike

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

部分代码在incidents表中插入新记录,其中字段begin_date(timestamp(3) with time zone)是一个创建时间戳,用now填充:

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

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

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

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 编写的(如果事务未提交,我不应该看到新记录,我有默认的序列化级别)。

此外,pg_stat_activity View 仅显示idle 连接。

有什么线索吗?

最佳答案

有常量(特殊时间戳值)'now'
还有函数 now()

您随意混合它们的事实表明您没有意识到最重要的区别。 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
-------------------------------+-------------------------------
<b>2016-06-11 03:09:05.622783+02 | 2016-06-11 03:09:05.622783+02</b> -- identical
(1 row)

test=# commit;
COMMIT
test=# EXECUTE foo;
now_constant | now_function
-------------------------------+------------------------------
<b>2016-06-11 03:09:05.622783+02 | 2016-06-11 03:10:00.92488+02</b> -- different!
(1 row)

虽然您在同一个事务 中运行两者,但'now'now() 产生相同的结果值(value)。但是准备好的语句旨在持续整个 session (可能跨越许多事务)。下次执行准备好的语句时,您会看到不同之处。

换句话说:'now' 实现了“早期绑定(bind)”,而 now() 实现了 < strong>“后期绑定(bind)”

您可能已经引入了准备好的语句和/或连接池(它可以将准备好的语句保留更长的时间)——这两个想法通常都是不错的。但是 INSERT 中隐藏的问题现在开始出现了。

您看到的“空闲连接”表明:连接保持打开状态,保留准备好的语句。

简而言之:使用 now()

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

关于postgresql - PostgreSQL : 'now' keeps returning same old value 问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37758022/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com