0
votes

I have an entity like this

@Entity
@Table(name = "ACC_ACCOUNT_INFO")
@Getter
@Setter
public class AccountInfoEntity implements Serializable {

@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "accountIdGenerator")
@SequenceGenerator(name = "accountIdGenerator", sequenceName = "SEQ_ACCOUNT")
@Id
@Column(name = "ID")
private long id;

@Column(name = "ACCOUNT_NO", nullable = false)
private String accountNo;

@Column(name = "ACCOUNT_TYPE", nullable = false)
@Enumerated(EnumType.STRING)
private AccountType accountType;

@Column(name = "ACCOUNT_NAME", nullable = false)
private String accountName;

@Column(name = "BANK_NAME", nullable = false)
private String bankName;

@Column(name = "EXPIRY_DATE", nullable = false)
private LocalDate expiryDate;

@Column(name = "STATUS", nullable = false)
private String accountStatus;

@Column(name = "PARENT_ACC_ID")
private Long parentAccountId;

@Column(name = "BALANCE", nullable = false)
private BigDecimal balance;

@Version
@Access(javax.persistence.AccessType.PROPERTY)
@Column(name = "VERSION")
private int version;

}

In my scenario an account balance can be updated concurrently.So if two request come at the same time to update same account balance one of the request succeed other one got optimistic lock. So then I tried to the update the account with PESSIMISTIC_WRITE lock mode. But still the optimistic lock error when concurrent requests arrive. Then I removed VERSION property (optimistic locking) from entity then all concurrent requests succeed for same account.

Now my question is, is it possible to use both locking mechanism ?

Update: For 5 concurrent call for same account with PESSIMISTIC_WRITE lock mode hibernate generate query like this

Hibernate: select * from acc_account_info accountinf0_ where accountinf0_.account_no=?
Hibernate: select * from acc_account_info accountinf0_ where accountinf0_.account_no=?
Hibernate: select * from acc_account_info accountinf0_ where accountinf0_.account_no=?
Hibernate: select * from acc_account_info accountinf0_ where accountinf0_.account_no=?
Hibernate: select * from acc_account_info accountinf0_ where accountinf0_.account_no=?


Hibernate: select id from acc_account_info where id =? and version =? for update
Hibernate: select id from acc_account_info where id =? and version =? for update
Hibernate: select id from acc_account_info where id =? and version =? for update
Hibernate: select id from acc_account_info where id =? and version =? for update
Hibernate: select id from acc_account_info where id =? and version =? for update

But If lock mode is PESSIMISTIC_FORCE_INCREMENT then hibernate do not generate select for update set of queries. So pessimistic lock is not working with PESSIMISTIC_FORCE_INCREMENT mode.

Here is my code

public AccountInfoEntity findByAccNoPessimistic(String accountNo) {
    Query query = em.createQuery("From AccountInfoEntity where accountNo=:accountNo");
    query.setParameter("accountNo", accountNo);
    query.setLockMode(LockModeType.PESSIMISTIC_FORCE_INCREMENT);
    AccountInfoEntity result = (AccountInfoEntity) query.getSingleResult();
    em.refresh(result);
    return result;
}
1

1 Answers

0
votes

When you retrieve an entity with LockModeType.PESSIMISTIC_WRITE in parallel, only one call should succeed and others should be blocked. Therefore it's strange that you faced an optimistic lock error.

In any case LockModeType.PESSIMISTIC_FORCE_INCREMENT + @Version is the suggested way to go and it kind of lets have both mechanisms in place. (I.e. by default there will be an optimistic lock and if explicitly asked - pessimistic).