2015-01-25 2 views
1

У меня возникла странная проблема «потерять» данные при обновлении данных с помощью Hibernate.Данные коллекции Hibernate теряются, когда две транзакции сохраняют данные одновременно

Приложение развернуто на JBoss AS 7, соединение с базой данных уровня изоляции к MySql БД установлен на READ_COMMITED.

Я сущности определяется через наследование как это:

@Entity 
@Table(name = "element") 
@Inheritance(strategy=InheritanceType.JOINED) 
public class ElementEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name="i_element", nullable=false) 
    private Integer iElement; 

    @Column(name="hash") 
    private String hash; 

    ... 
} 

@Entity 
@Table(name = "element_a") 
@PrimaryKeyJoinColumn(name="i_element") 
public class AElementEntity extends ElementEntity { 
    ... // some primitive fields 
} 

@Entity 
@Table(name = "element_b") 
@PrimaryKeyJoinColumn(name="i_element") 
public class BElementEntity extends ElementEntity { 
     ... // some primitive fields 
} 

@Entity 
@Table(name = "element_c") 
@PrimaryKeyJoinColumn(name="i_element") 
public class CElementEntity extends ElementEntity { 
     ... // some primitive fields 

     @OneToMany(mappedBy="cElement", cascade=CascadeType.ALL) 
     private List<NodeEntity> nodes; 
} 


@Entity 
@Table(name="node") 
public class NodeEntity { 

    @Id 
    @GeneratedValue(strategy = GenerationType.AUTO) 
    @Column(name = "i_node")  
    private Integer iNode; 

    @ManyToOne 
    @JoinColumn(name="i_element", referencedColumnName="i_element") 
    private CElementEntity cElement; 

    ... // some primitive fields 
} 

и реализация дао как это:

public class ElementDaoImpl implements ElementDao { 
    private static final Logger logger = Logger.getLogger(ElementDaoImpl.class); 

    private EntityManager entityManager; 

    public ElementDaoImpl(EntityManager entityManager) { 
     super(); 
    } 

    @Override 
    public List<ElementEntity> load(String hash) { 

     // nacist vsechny elementy pro SGL 
     Query query = entityManager.createQuery("FROM " + ElementEntity.class.getSimpleName() + " WHERE hash = :hash"); 
     query.setParameter("hash", hash); 
    List<ElementEntity> elements = (List<ElementEntity>) query.getResultList(); 
    //.. log C element 
     return elements; 
    } 

    @Override 
    public void save(String hash, List<ElementEntity> elements) { 
     removeElementsByHash(hash); 

     for (ElementEntity element : elements) { 
      if (logger.isDebugEnabled()) { 
       if (element instanceof CElement) { 
        CElementEntity cElementEntity = (CElementEntity) element; 
        logger.debug("Storing for hash " + hash + " nodes " + cElementEntity.getNodes()); 
       } 
      } 
      entityManager.persist(entity); 
      entityManager.flush(); 
     } 

     entityManager.clear(); 

    } 

    private void removeElementsByHash(String hash) { 
     Query query = getEntityManager().createQuery("FROM " + ElementEntity.class.getSimpleName() + " WHERE hash = :hash"); 
     query.setParameter("hash", hash); 
     List<ElementEntity> entities = (List<ElementEntity>) query.getResultList(); 

     if (entities != null && !entities.isEmpty()) { 
      for (ElementEntity entity : entities) { 
       entityManager.remove(entity); 
      } 
     } 
     entityManager.flush(); 
     entityManager.clear(); 
    } 
} 

дао создается в EJB без гражданства фасоли:

@Stateless(name=ElementServiceBean.NAME, mappedName=ElementServiceBean.NAME) 
@Local({ElementService.class}) 
@LocalBinding(jndiBinding=ElementServiceBean.NAME) 
public class ElementServiceBean implements ElementService { 

    public static final String NAME = "ElementServiceBean"; 

    @PersistenceContext(unitName = "coredb_em") 
    protected EntityManager entityManager; 

    private ElementDao elementDao; 

    @PostConstruct 
    public void init() { 
    this.elementDao = new ElementDaoImpl(entityManager); 
    } 

    @Override 
    public List<ElementEntity> load(String hash) { 
     return elementDao.load(hash); 
    } 

    @Override 
    public void save(String hash, List<ElementEntity> elements) { 
     elementDao.save(hash, elements); 
    } 
} 

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

Я не использую блокировку Hibernate. Никакое исключение не выбрасывается. Просто данные из коллекции «узлы» теряются.

Так что мой вопрос сейчас, как это возможно? Я неправильно использую методы очистки и очистки в dao-слое?

Или мне действительно нужен какой-либо спящий режим/блокировка базы данных (но зачем мне это нужно, когда я удаляю все строки элементов с заданным хешем, прежде чем я их сохраню)? Если я хорошо понимаю это в CMT, транзакция завершается, когда транзакция заканчивается.

Вот журнал log4j:

[2015-01-22 17:02:49,944] 9023579 [Thread-208] DEBUG ElementDaoImpl Storing for hash ABCDE nodes nodes=[NodeEntity[1], NodeEntity[2]] 
[2015-01-22 17:02:50,028] 9023663 [Thread-216] DEBUG ElementDaoImpl Storing for hash ABCDE nodes nodes=[NodeEntity[1], NodeEntity[2]] 
[2015-01-22 17:02:50,727] 9024362 [Thread-208] DEBUG ElementDaoImpl CElementEntity nodes: []] 

Спасибо за каждый кончике или совет как улучшить код.

ответ

4

Вам необходимо добавить @Version вашим объектам, чтобы включить optimistic locking и, следовательно, предотвратить lost updates.

Для этого ваших лиц должны содержать следующие поля:

@Version 
private int version; 

Hibernate позаботится об остальном.

 Смежные вопросы

  • Нет связанных вопросов^_^