Sorunun çok bilinen bir cevabı var. Bir kaydı güncelleme yaparken kilitlemek (locking) bunun bilinen çözümü.
Yani kaydı Oracle kullanırken sorgu ile çekip arkasına "for update" yaparsan kaydı kitlemiş olursun. Bu yaklaşım db üzerinden otomatik desteklenen bir yaklaşım oluyor ve buna pesimistic locking deniyor. Bunun pesimistic olan kısmı şöyle oluyor. Eğer bu for update işini tek bir kayıt için değil de yanlışlıkla bütün tablo için atarsan tabloyu kilitlemiş olursun ki insanlar okuyamaz bile. Ayrıca commit/rollback yapmadığın sürece bu kayıt kitli kalır. DB session düşene kadar kaydı kapalı tutarsın.
Diğer yaklaşımın adı optimistic locking. Bu yaklaşımda da tablona bir kolon daha eklersin, ismi genelde version olur. Her update işleminde bu kaydı bir arttırırsın.
update members m
set name = 'kenan',
version = version + 1
where id = :id
and version = :version
Bu yapıda dışarıdan id = 5 geçerken ayrıca member version bilgisini de alırsın onu da parametre olarak geçersin. Birisi o arada versiyonu artırdıysa misal sen select attığında 3 idi update ederken 4 o zaman zaten where koşuluna uymadığı için update edebileceği bir kayıt bulamayacak. Update işleminin sonucuna bakacaksın kaç kayıt update edilmiş diye (%rowcount) eğer 1 ise sıkıntı yok.
Optimistic locking desteğini hibernate de verir. @Version diye bir annotation vardı yanlış hatırlamıyorsam.