The 30 second answer
Both read the same balance, both subtract, and the second write overwrites the first, so one debit is lost. Read Committed does not prevent this. I either lock the row with SELECT FOR UPDATE, so the second waits and sees the new balance, or use optimistic locking with a version column, so the second update fails and retries. A single conditional UPDATE also works for simple cases.
The lost update. Two transactions read balance 100, each subtracts 30, each writes 70. The account should be at 40. Under PostgreSQL's default Read Committed level both updates succeed. Three fixes:
1. Pessimistic locking. SELECT ... FOR UPDATE locks the row; the second transaction waits until the first commits, then reads the new balance. In JPA, @Lock(LockModeType.PESSIMISTIC_WRITE) on a repository method produces it. Lock accounts in a fixed order, for example by ID, so two opposite transfers cannot deadlock; see the lock-ordering scenario. Good when conflicts are frequent, as on a hot account.
2. Optimistic locking. A @Version column is checked in the UPDATE ... WHERE id = ? AND version = ?. If another transaction changed the row first, no row matches and JPA throws OptimisticLockException (Spring translates it to ObjectOptimisticLockingFailureException). Retry the whole transaction a bounded number of times. Good when conflicts are rare; no locks are held while the user thinks.
@Entity
class Account {
@Id Long id;
@Version long version;
BigDecimal balance;
}3. One atomic statement. UPDATE account SET balance = balance - :amt WHERE id = :id AND balance >= :amt reads and writes in one step; zero updated rows means insufficient funds. Simplest when the rule fits in SQL.
Isolation levels. Under Repeatable Read, PostgreSQL detects the conflict itself and fails the second transaction with "could not serialize access due to concurrent update", which also needs a retry.
Across services. Locks only protect one database. For a transfer between services or a request that may be retried, add an idempotency key; see the distributed transaction question.