RDB をたまにしか使ってないとロックみたいな複雑なところは こういうときにどうなるんだっけ?と思って毎回調べてたりするのでメモ代わりに

UPDATE 時の WHERE で更新日時が等しいことを条件としていれば上書きされることはないはず と思ってたけど トランザクションが同時実行された場合は

1: トランザクション A が書き換えようとする
  条件に一致するので正常に書き換えできる

2: トランザクション B が書き換えようとする
  A がコミットされてないので古いバージョンが見えている
  条件に一致するので正常に書き換えできる

3: トランザクション A をコミットする
4: トランザクション B をコミットする
5: A の書き換えが消える

になるような気がする
これが困るなら同時実行されないように分離レベルとか設定必要なんだっけ?

試したほうが早いと思ってやってみると PostgreSQL のデフォルトだと特に問題なかった

begin;
select * from tt;

id | v | updated_at
----+---+---------------------
1 | 1 | 2021-07-01 09:00:00
(1 row)

update tt set
v = 2,
updated_at = '2021-07-01 10:00:00'
where id = 1
and updated_at = '2021-07-01 09:00:00';

select * from tt;

id | v | updated_at
----+---+---------------------
1 | 2 | 2021-07-01 10:00:00
(1 row)
begin;
select * from tt;

id | v | updated_at
----+---+---------------------
1 | 1 | 2021-07-01 09:00:00
(1 row)

update tt set
v = 3,
updated_at = '2021-07-01 10:00:10'
where id = 1
and updated_at = '2021-07-01 09:00:00';

-- 待機状態
commit;
select * from tt;

id | v | updated_at
----+---+---------------------
1 | 2 | 2021-07-01 10:00:00
(1 row)
-- コミットされたので update の処理が終わる

select * from tt;
id | v | updated_at
----+---+---------------------
1 | 2 | 2021-07-01 10:00:00
(1 row)

-- 更新されてない

B 側の UPDATE 時にロックされてて UPDATE が処理されず A 側がコミットされてから処理される
その結果 更新日時が違うので B の更新はされてない

余計な心配だったみたい