如何在读写操作之间锁定表

时间:2015-11-13 19:28:07

标签: 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 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'。 接下来发生的事情是2 trx使用相同的值。首次提交的trx将成功,第二次将由于唯一约束异常而失败。

因此,我需要在读取最新的商业价值时锁定发票表。我认为这个锁应该是活动的,直到新的Invoice实体保存到DB。

我应该如何在Hibernate中执行此操作?

2 个答案:

答案 0 :(得分:4)

您可以使用悲观锁定,而不是使用冲突检测并发控制机制,例如依赖于唯一约束或optimistic locking

你需要:

  1. 一个InvoiceSequence表,其中有一个实体映射到它
  2. 此表只有一行,存储最新的发票序列值
  3. 您在记录中acquire an exclusive lock

    InvoiceSequence invoiceSequence = em.find(InvoiceSequence.class, 1L, LockModeType.PESSIMISTIC_WRITE)
    
  4. 使用业务逻辑递增序列并修改实体以存储最新值:

    String currentSequence = invoiceSequence.getValue();
    String nextSequence = sequenceGenerator.nextValue(currentSequence);
    invoiceSequence.setValue(nextSequence);
    
  5. 独占锁也会阻止并发读写。我的High-Performance Java Persistence书有一个关于交易的非常详尽的章节,你可能会发现它也很有用。

答案 1 :(得分:1)

序列是一组整数1,2,3,...按需按顺序生成。序列经常在数据库中使用,因为许多应用程序要求表中的每一行都包含唯一值,序列提供了一种生成它们的简便方法。

你可以做的一种方式

class BusinessFactory {
public String createUniqueValue() {
    String valueNotUsed = (String) getSession().createSQLQuery("select nextval('hibernate_sequence')");    

   // generate new value 

   return newValue;
}}
相关问题