Oracle systimestamp в условии запроса в другом часовом поясе - PullRequest
0 голосов
/ 25 апреля 2020

У меня следующий код с использованием столбца lock_until TIMESTAMP(3). Код вставляет systimestamp + 5 minutes, а затем выделяет все строки с помощью lock_until < systimestamp. Я не ожидал бы, что в результирующем наборе нет строк, так как lock_until находится в будущем, но строка возвращается. Наиболее вероятная причина в том, что мой местный часовой пояс UTC + 2, но я не понимаю, как это возможно. Код работает, как и ожидалось, с current_timestamp, но я бы предпочел, чтобы код не зависел от часового пояса клиента.

jdbcTemplate.update("delete from shedlock where name = 'test'");
System.out.println(jdbcTemplate.queryForList("SELECT SESSIONTIMEZONE FROM dual"));
// insert, lock_until is now + 5 minutes
jdbcTemplate.update("INSERT INTO shedlock(name, lock_until, locked_at, locked_by) VALUES('test', systimestamp + 5/(24 * 60), systimestamp, 'me')");
// select if lock_until <= systimestamp
System.out.println(jdbcTemplate.queryForList("select * from shedlock where lock_until <= systimestamp"));
// systimestamp ?
System.out.println(jdbcTemplate.queryForList("select systimestamp from dual"));

приводит к

Local time: 17:32:48.872
[{SESSIONTIMEZONE=Europe/Prague}]
[{NAME=test, LOCK_UNTIL=2020-04-25 15:37:49.0, LOCKED_AT=2020-04-25 15:32:49.106, LOCKED_BY=me}]
[{SYSTIMESTAMP=2020-04-25 17:32:49.168954}]

1 Ответ

1 голос
/ 25 апреля 2020

Из документации Oracle :

SYSTIMESTAMP возвращает системную дату, включая доли секунды и часовой пояс системы, в которой находится база данных. Тип возвращаемого значения TIMESTAMP WITH TIME ZONE.

Когда вы делаете:

INSERT INTO shedlock (
  name,
  lock_until,
  locked_at,
  locked_by
) VALUES (
  'test',
  systimestamp + 5/(24 * 60),
  systimestamp,
  'me'
)

Это неявно делает:

INSERT INTO shedlock (
  name,
  lock_until,
  locked_at,
  locked_by
) VALUES (
  'test',
  CAST( systimestamp + 5/(24 * 60) AS TIMESTAMP(3) ),
  CAST( systimestamp AS TIMESTAMP(3) ),
  'me'
)

, который будет отбрасывать часовой пояс информацию и оставьте другие компоненты даты / времени как есть.

Однако, когда вы делаете SELECT, это неявно делает:

select *
from   shedlock
where  FROM_TZ( lock_until, SESSIONTIMEZONE ) <= systimestamp

и добавление часового пояса сеанса к сохраненное значение и затем сравнение его с временной меткой с часовым поясом системы, в которой находится база данных; если эти два часовых пояса не совпадают, вы получите неожиданно включенные / исключенные строки.

Вместо этого вы можете явно преобразовать SYSTIMESTAMP из типа данных TIMESTAMP WITH TIME ZONE в данные TIMESTAMP тип:

select *
from   shedlock
where  lock_until <= CAST( systimestamp AS TIMESTAMP(3) )

дБ <> скрипка

...