我有一个情况,每个新记录都应该包含一个独特且可读的值。这个值对于用户具有业务意义,并将作为自然ID(除主键外)在我们的数据库中处理。
为了让您了解该值的结构:
- record 1 has business value 'INVOICE_AAA_001'
- record 2 has business value 'INVOICE_AAA_002'
...
- record 999 has business value 'INVOICE_AAA_999'
- record 1000 has business value 'INVOICE_BAA_001'
- record 1001 has business value 'INVOICE_BAA_002'
...
这个企业价值通过工厂来创造:
class BusinessFactory {
...
public String createUniqueValue() {
String lastValue = (String) getSession().createQuery("select businessValue " +
"from Invoice as invoice " +
"order by businessValue")
.setMaxResults(1)
.setReadOnly(true)
.uniqueResult();
// generate new value
return newValue;
}
}
服务层将调用工厂并保存新的发票:
@Transactional
public void saveNewInvoice() {
final String newValue = businessFactory.createUniqueValue();
Invoice invoice = new Invoice(newValue);
invoiceRepository.save(invoice);
}
这里的问题是,有可能出现trx1和trx2同时读取'INVOICE_BAA_002'业务值的情况。接下来会有两个事务同时使用相同的值。第一个提交的事务将成功,第二个事务将由于唯一约束异常而失败。
因此,当读取最新的业务值时,我需要在发票表上放置一个锁。我认为该锁应该在将新发票实体保存到数据库之前一直保持活动状态。
在Hibernate中,我该如何做呢?