Все, абсолютно все люди путают транзакции с блокировками. Это какая-то массовая галлюцинация.
Хотя там все просто, как 2х2
Транзакции используются для консистентности. Чтобы когда выполняется больше одного запроса, изменяющего данные, то были выполнены либо все, либо ни одного.
А чтобы не было race condition используются блокировки.
Делаете SELECT FOR UPDATE, который блокирует строку, чтобы больше никто из нее не мог читать. Любой процесс, который захочет прочесть это же значение, будет стоять и ждать.
Дальше вы делаете свои проверки, и потом сам апдейт, который отпустит блокировку.
Процесс, который ждал своей очереди, получит уже измененное значение, и проверка не пройдет.