2016-12-09 5 views
1

У меня есть проблема, связанная с синглетом EJB и блокировкой базы данных.EJB Singleton и JPA оптимистичные блокирующие броски OptimisticLockException

Следующий класс представляет собой сущность для номеров консигнаций. Обязательно, чтобы каждый номер консигнации был уникальным. Обратите внимание, что этот класс был подготовлен для оптимизации блокировки путем определения свойства версии.

@Entity 
@NamedQuery(name = Connote.FIND_NEXT, query = "SELECT c from Connote c WHERE c.consumed = false") 
public class Connote implements Serializable { 

    /** 
    * 
    */ 
    private static final long serialVersionUID = 1L; 
    public static final String FIND_NEXT = "Connotes.FindNext"; 

    @Id 
    @Size(max = 15) 
    private String connote; 

    @Version 
    private Long version; 

    private Date insertedDate; 
    private boolean consumed; 
    private Date consumedDate; 

    public Connote() { 
     super(); 
    } 

    public String getConnote() { 
     return connote; 
    } 

    public void setConnote(String connote) { 
     this.connote = connote; 
    } 

    public Date getInsertedDate() { 
     return insertedDate; 
    } 

    public void setInsertedDate(Date insertedDate) { 
     this.insertedDate = insertedDate; 
    } 

    public boolean isConsumed() { 
     return consumed; 
    } 

    public void setConsumed(boolean consumed) { 
     this.consumed = consumed; 
    } 

    public Date getConsumedDate() { 
     return consumedDate; 
    } 

    public void setConsumedDate(Date consumedDate) { 
     this.consumedDate = consumedDate; 
    } 

    public Long getVersion() { 
     return version; 
    } 

    public void setVersion(Long version) { 
     this.version = version; 
    }  
} 

Подающая компания предоставляет набор многих номеров тысяч консигнации, которые будут сохранены в базе данных.

При создании нового заказа на фрахт должен быть доставлен и доставлен следующий запрашиваемый сервис следующего «необработанного» консигнационного номера из этого набора .

Служба в этом случае представляет собой одноэлементный EJB, который предоставляет метод обслуживания «calculateConnoteNumber()». Поскольку класс ejb аннотируется с помощью «@Lock (LockType.WRITE)» , следует избегать одновременного доступа к этому методу. После извлечения следующего необработанного объекта флаг «потребляется» будет помечен как true, и будет установлена ​​дата потребления. Наконец, обновленный объект будет объединен и значение connote будет возвращено.

Однако во время тестирования нагрузки мы испытали «OptimisticLockExceptions» (средн 5 из 1000) при создании новых заказов.

То, что я не понимаю, как это возможно, так как доступ к бизнес-методу и , таким образом, транзакция должна быть последовательной.

Изменение типа запирающий на сохранение слоя путем установки

query.setLockMode(LockModeType.PESSIMISTIC_WRITE); 

работы.

На мой взгляд, это не должно быть необходимым, и оптимистичная блокировка должна быть достаточной, пока не будет разрешен одновременный доступ к бизнес-методу . Я что-то пропустил?

среда используется: WildFly 8.2.0, MySql 5,7, ха-DataSource

/** 
* Session Bean implementation class ConnoteCalculatorFacade 
*/ 
@Singleton 
@ConcurrencyManagement(ConcurrencyManagementType.CONTAINER) 
@TransactionManagement(TransactionManagementType.CONTAINER) 
@Lock(LockType.WRITE) 
public class ConnoteCalculatorFacade { 

    private final Logger logger = LoggerFactory.getLogger(this.getClass()); 

    @PersistenceContext(unitName = "some_unit_name") 
    private EntityManager entityManager; 

    /** 
    * Default constructor. 
    */ 
    public ConnoteCalculatorFacade() { 
     if (logger.isDebugEnabled()) { 
      logger.debug("ConnoteCalculatorFacade instantiated!"); 
     } 
    } 

    @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 
    public String calculateConnoteNumber() throws OrderManagementException { 
     if (logger.isInfoEnabled()) { 
      logger.info("Retrieving new RS connote!"); 
     } 

     try { 
      Query query = this.entityManager.createNamedQuery(Connote.FIND_NEXT); 
      query.setMaxResults(1); 
      //query.setLockMode(LockModeType.PESSIMISTIC_WRITE); <-- works when using pessimistic_write 

      List<Connote> validConnoteList = query.getResultList(); 

      if (validConnoteList.size() == 1) { 

       Connote connote = validConnoteList.get(0); 
       connote.setConsumed(true); 
       connote.setConsumedDate(new Date()); 

       this.entityManager.merge(connote); 
       this.entityManager.flush(); 

       return connote.getConnote(); 
      } else { 
       throw new OrderManagementException(AddressLabelExceptionReason.NO_CONNOTES_AVAILABLE); 
      } 

     } catch (Exception e) { 
      logger.error("Error calculating connote number! ",e); 
      throw new OrderManagementException(AddressLabelExceptionReason.ERROR_ASSIGNING_CONNOTE); 
     } 

    } 
} 

Update Услуга потребляется другим лицом без, местного EJB "PDFCreatorFacade", который впрыскивает одноплодной

@EJB 
private ConnoteCalculatorFacade connoteCalculator; 
... 

, а затем вызывает метод на одноэлементном методе (не аннотированный).

public Label createPdfDocument(Label label) throws OrderManagementException { 
    .... 
    String connoteNumber = connoteCalculator.calculateConnoteNumber(); 
    .... 
} 
+0

Является ли это единой системой узлов? –

+0

Да, это единая система узлов. – chrisF

+0

Можете ли вы опубликовать код, который вызывает метод 'calculateConnoteNumber' ... Как вы вызываете (или вводите) ваше определение EJB Singleton? –

ответ

1

Вы получаете этот эффект, потому что вы не указали @ TransactionAttribute(REQUIRES_NEW) на вашем методе calculateConnoteNumber.

Этот метод вызывается несколькими клиентами, которые, как я ожидаю, также являются EJB. Первый EJB в цепочке вызовов запустит транзакцию и впоследствии попытается зафиксировать транзакцию, все за пределами ваших средств контроля параллелизма.

+0

SteveC, спасибо за ваш ответ. Извините, я допустил ошибку при публикации вопроса. Бизнес-метод действительно был аннотирован с помощью @TransactionAttribute (TransactionAttributeType.REQUIRES_NEW), я удалил его при переходе на пессимистическую блокировку и забыл вернуть его на этот вопрос. (Обновил мой вопрос сейчас) Все еще есть OptimisticLockingExceptions (сред. 5/1000) с тестовый документ предоставлен в моем вопросе. – chrisF

+0

Было бы полезно попробовать WildFly 10.1. Возможно, вы столкнулись с хорошей старомодной ошибкой в ​​реализации сервера –