Careeroza
Real World Example
Paytm-Style Wallet Transfer
A wallet transfer must debit one wallet and credit another in one transaction. Dirty checking means the service only changes fields; Hibernate writes both UPDATEs at commit, or nothing if an exception rolls back:
@Entity
@Table(name = "wallets")
public class Wallet {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private Long userId;
@Column(nullable = false, precision = 12, scale = 2)
private BigDecimal balance;
public void debit(BigDecimal amount) {
if (balance.compareTo(amount) < 0) throw new InsufficientBalanceException(id);
balance = balance.subtract(amount);
}
public void credit(BigDecimal amount) { balance = balance.add(amount); }
}
@Service
public class WalletService {
private final EntityManager em;
public WalletService(EntityManager em) { this.em = em; }
@Transactional
public void transfer(Long fromId, Long toId, BigDecimal amount) {
Wallet from = em.find(Wallet.class, fromId); // MANAGED
Wallet to = em.find(Wallet.class, toId); // MANAGED
from.debit(amount); // may throw -> rollback, no SQL written
to.credit(amount);
em.persist(new WalletTransaction(fromId, toId, amount)); // TRANSIENT -> MANAGED
} // commit: INSERT transaction, UPDATE from, UPDATE to
}SQL at Commit
Request and SQL
curl -X POST localhost:8080/api/wallet/transfer -H "Content-Type: application/json" -d '{"fromId":1,"toId":2,"amount":500.00}'Example output
Hibernate: select w1_0.id,w1_0.balance,w1_0.user_id from wallets w1_0 where w1_0.id=?
Hibernate: select w1_0.id,w1_0.balance,w1_0.user_id from wallets w1_0 where w1_0.id=?
Hibernate: insert into wallet_transactions (amount,from_wallet_id,to_wallet_id) values (?,?,?)
Hibernate: update wallets set balance=?,user_id=? where id=?
Hibernate: update wallets set balance=?,user_id=? where id=?
HTTP/1.1 200 OK
{"status":"SUCCESS","amount":500.00}Note: Two users transferring from the same wallet at the same moment can still cause a lost update. Real payment systems add optimistic locking with @Version or pessimistic locks — covered in the advance level.