Immer wieder ähnliche Konzepte.
Konkurierende Updates sind bei Journalisierung und Transaktionen nicht möglich, das erhöht die Sicherheit. Transaktionen sollten möglichst kurz sein.
Mit SQL sind aber tatsächlich auch ohne Transaktion konkurierende Updates durchaus möglich.
Man beachte nur folgendes:

Additive Updates, die man per "set f = f +/- n" sind unproblematisch.
Statische Updates, die man per "set f = n" durchführt sollten Themenbezogen sein.

In .Net gibts ein kleines Framework, dass mir Updatecommand automatisch generiert.
Diese werden auf DataTable-Objekte angewendet und diese enthalten je Zeile und Spalte einen Original und Current-Value.
Der Update wird daher automatisch ergänzt per "where f = oldvalue ...." je Spalte des Selects.
Da steht es außer Frage, dass der Select nach möglichkeit nur die zu ändernden Spalten enthalten sollte.
Über eine Error-Auflistung erhält man die Zeilen, die nicht geändert werden konnten.

Und zu guter letzt:
In manchen DB's gibts Satzversionen. Z.B. bei der Firebird werden Satzversionen vorgehalten, so dass bei entsprechender Transaktion keine Schmutzdaten (dirty reads) vorkommen. Beim Update gibts einen Fehler, wenn die Satzversion bereits neuer ist als für die Transaktion erwartet.
Beim SQL-Server ist das wohl eher rudimentär. Da gibts die Satzversion nur beim After-Update-Trigger und wiederholten Updates, da der SQL-Server keine Before-Trigger kennt (große Schwachstelle).