Go + PostgreSQL: почему NOW() врёт о времени выполнения ⏱️
Представим обычный go-сервис, который обрабатывает заказ в транзакции PostgreSQL.
Кажется логичным ожидать, что updated_at будет примерно на пять секунд позже created_at.
Но это не так. В PostgreSQL NOW() возвращает время начала текущей транзакции. Значение не меняется, даже если внутри транзакции прошло несколько секунд или минут. В результате created_at и updated_at могут оказаться одинаковыми. Как исправить?
Всё зависит от того, какое именно время нам нужно.
- Время начала текущей транзакции SELECT NOW(); - Время начала выполнения текущего SQL-запроса SELECT statement_timestamp(); - Фактическое текущее время
SELECT clock_timestamp();
Если updated_at должен отражать фактический момент выполнения обновления, можно использовать:
UPDATE orders SET status = $1, updated_at = clock_timestamp() WHERE id = $2;
При этом NOW() не сломан. Его поведение полезно, когда все изменения одной транзакции должны иметь согласованную временную отметку. Что важно помнить в go?
Если транзакция включает несколько запросов, длительную обработку или ожидание других операций, не стоит автоматически считать NOW() временем выполнения конкретного запроса.
Сначала определите семантику поля: created_at для единого времени создания в рамках транзакции часто подходит NOW().
updated_at для фактического момента обновления может требовать clock_timestamp().
Для времени начала каждого sql-запроса подходит statement_timestamp(). Небольшой нюанс, который легко пропустить, а потом долго искать причину одинаковых временных меток в логах и таблицах.