Java 如何在读写操作之间锁定表
我遇到的情况是,每个新记录都应该包含一个唯一且可读的值。 该值对用户具有业务意义,并将在数据库中作为自然id(主键旁边)处理 要让您了解价值结构,请执行以下操作:Java 如何在读写操作之间锁定表,java,hibernate,jpa,transactions,locking,Java,Hibernate,Jpa,Transactions,Locking,我遇到的情况是,每个新记录都应该包含一个唯一且可读的值。 该值对用户具有业务意义,并将在数据库中作为自然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 1
- 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读取业务价值“发票_BAA_002”。
接下来发生的是两个trx使用相同的值。第一次提交的trx将成功,第二次将由于唯一约束异常而失败
因此,我需要在读取最新业务价值时锁定发票表。我认为在将新发票实体保存到DB之前,此锁应该处于活动状态
在Hibernate中应该如何执行此操作?序列是一组整数1、2、3、。。。按需按顺序生成的。序列经常在数据库中使用,因为许多应用程序要求表中的每一行都包含唯一的值,而序列提供了一种生成序列的简单方法 你能做的一件事
class BusinessFactory {
public String createUniqueValue() {
String valueNotUsed = (String) getSession().createSQLQuery("select nextval('hibernate_sequence')");
// generate new value
return newValue;
}}
您可以使用悲观锁定,而不是使用冲突检测并发控制机制(例如依赖于唯一约束或约束) 您需要:
InvoiceSequence
表
InvoiceSequence invoiceSequence = em.find(InvoiceSequence.class, 1L, LockModeType.PESSIMISTIC_WRITE)
String currentSequence = invoiceSequence.getValue();
String nextSequence = sequenceGenerator.nextValue(currentSequence);
invoiceSequence.setValue(nextSequence);
独占锁也将防止并发读写。序列可以帮助您。你能创建一个吗?我不知道如何创建序列。你能给我更多的信息吗?序列是否阻止两个使用相同值的并发事务?此处的名称
lastUniqueValue
具有误导性,因为您获得的值已经是未使用的值。nextval
返回下一个未使用的值,以便您可以直接使用。感谢您的回复。nextval(“hibernate_序列”)是hibernate还是特定于数据库?这项功能是否适用于所有关于防止方言的数据库?请参阅:再次感谢您的回复。但我怀疑“nextval”在这种情况下是否有用,因为我还必须管理字母数字位置(AAA、BAA、BBA…),因此我认为我确实需要读取最新插入记录的业务价值并应用锁。您可以捕获最后插入的记录以生成字母。然后得到序列的一个新值,并和字母STHX合并为您的答案!我想我必须定义某种类型的锁超时,以防止另一个trx不确定地等待,并确保锁将被释放?也许我还应该添加一个特性,自动重试由于锁定超时而失败的trx?