Eclipselink с JTA не находит вновь вставленный объект и выдает исключение Duplicate Key Exception

Я хочу сохранить список объектов JPA в базе данных MySQL, используя JTA (транзакции, управляемые контейнером) с EclipseLink на сервере приложений Glassfish 3.1.2.

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

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

Как я могу сказать EntityManager (или кому-то еще :-)), что вновь вставленные объекты должны быть доступны немедленно?

Любая помощь приветствуется ...

МОЙ ЛИЦ

пакет clearquest.crud.domain; import java.io.Serializable;

import javax.ejb.Lock; import javax.ejb.LockType; import javax.persistence. *;

import java.util.List;

@Entity @Table (name = "eom") @NamedQueries ({@NamedQuery (name = "Eom.findAll", query = "SELECT e FROM Eom e"), @NamedQuery (name = "getEomByProjectName", query = "SELECT e FROM Eom e WHERE e.projectname =: projectname ")}) открытый класс Eom реализует сериализуемый {частный статический окончательный длинный serialVersionUID = 1L; private String имя проекта; частные дефекты списка;

public Eom() {
}


@Id
@Column(unique=true, nullable=false, length=150)
public String getProjectname() {
    return this.projectname;
}

public void setProjectname(String projectname) {
    this.projectname = projectname;
}

Мой DAO

пакет clearquest.crud.domain; import java.io.Serializable;

import javax.ejb.Lock; import javax.ejb.LockType; import javax.persistence. *;

import java.util.List;

@Stateless @Singleton публичный класс EomDao реализует EomDaoLocal {

private @PersistenceContext(unitName = "emiClearQuestAdapterPersistancy")
EntityManager em;

@Override
public void storeEom(Eom eom) {
    em.persist(eom);
}

@Override
public void updateEom(Eom eom) {
    em.merge(eom);
}

@Override
public void deleteEom(Eom eom) {
    em.remove(eom);
}

@Override
public Eom getEomByProjectName(String projectName) throws NotFoundException {
    em.getEntityManagerFactory().getCache().evictAll();
    return em.find(Eom.class, projectName);
}

@Override
public boolean existsEom(String projectName) {
    try {
        if (this.getEomByProjectName(projectName) != null) {
            return true;
        } else {
            return false;
        }
    } 
    catch (NotFoundException e) {
        return false;
    }
}

}

И ФАСАД

пакет clearquest.crud.domain; import java.io.Serializable;

import javax.ejb.Lock; import javax.ejb.LockType; import javax.persistence. *;

import java.util.List;

@Stateless @Singleton общедоступный класс DefectListFacade реализует DefectListFacadeLocal {

private @EJB
DefectDaoLocal defectdao;
private @EJB
EomDaoLocal eomdao;

@Override
public void insertdefect(CQDefect defect) {

    String projectName = defect.getFehlerprojektnummer().getLabel();

    Eom eom = new Eom();
    eom.setProjectname(projectName);

    Defect domaindefect = new Defect();
    List<Defect> defectlist = new ArrayList<Defect>();

    transferJsonToDomain(domaindefect, defect);
    domaindefect.setEom(eom);
    defectlist.add(domaindefect);
    eom.setDefects(defectlist);

    eomdao.storeEom(eom);

    Logger.getLogger(DefectListFacade.class.getName()).info(
            "EOM -- INSERTED " + eom.getProjectname());
}

@Override
public void updatedefect(CQDefect defect) {

    String projectName = defect.getFehlerprojektnummer().getLabel();

    Logger.getLogger(DefectListFacade.class.getName()).info(
                "EOM -- UPDATED " + projectName);
}

И ЭТО МОЕ СООБЩЕНИЕ

@Override
public void receiveMessage(BaseMessage message) {
    if (message instanceof FehlerMessage) {
        FehlerMessage fehlermsg = (FehlerMessage) message;
        if (eomdao.existsEom(fehlermsg.getEom())) {
            defectlistfacade.updatedefect(fehlermsg.getFehler());
        } else {
            defectlistfacade.insertdefect(fehlermsg.getFehler());
        }
        Logger.getLogger(FehlerMessageReceiver.class.getName()).fine(
                fehlermsg.getEom() + " - "
                        + fehlermsg.getFehler().getFehler_Titel());
        monitoring.notifyEMDBMessageReceive(BusType.Base,
                message.getTypeIdentifier(), message.getSize());
    }
}

Сделав то, что сказал Крис, я узнал, что происходит. Это своего рода состояние гонки.

[# | 2014-03-27T11: 22: 39.051 + 0100 | ИНФОРМАЦИЯ | glassfish3.1.2 | com.generali.tools.myemi.components.clearquest.crud.facade.DefectListFacade | _ThreadID = 2605; _ThreadName = Thread-10; | EOM - ВСТАВЛЕННЫЙ PRJ-00359 | #]

[# | 2014-03-27T11: 22: 39.051 + 0100 | ИНФОРМАЦИЯ | glassfish3.1.2 | com.generali.tools.myemi.components.clearquest.crud.facade.DefectListFacade | _ThreadID = 2603; _ThreadName = Thread-10; | EOM - ВСТАВЛЕННЫЙ PRJ-00359 | #]

[# | 2014-03-27T11: 22: 39.051 + 0100 | ПРЕДУПРЕЖДЕНИЕ | glassfish3.1.2 | javax.enterprise.system.core.transaction.com.sun.jts.jta | _ThreadID = 2605; _ThreadName = Thread-10; | JTS5054: Непредвиденная ошибка произошла после завершения

Стек локальных исключений: Исключение [EclipseLink-4002] (Eclipse Persistence Services - 2.3.2.v20111125-r10461): org.eclipse.persistence.exceptions.DatabaseException Внутреннее исключение: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityationConceptionVision «PRJ-00359» для ключа «PRIMARY». Код ошибки: 1062. Вызов: INSERT INTO eom (PROJECTNAME) VALUES (?) Bind => [1 параметр bound]

Есть 2 сообщения JMS, которые идут рядом друг с другом с одинаковым именем EOM (первичным ключом), и номер потока 2605 сначала вставляет EOM. Но есть еще один поток с номером 2603, который также вставляет тот же первичный ключ сразу после первой вставки. Во всяком случае, второй поток не знает о первой вставке.

Теперь возникает вопрос, как я могу заблокировать, чтобы вторая вставка ожидала завершения первой?


person i-developer    schedule 26.03.2014    source источник
comment
Установите для ведения журнала eclipselink значение «Fine» или «Finest», чтобы видеть транзакцию, SQL и другие сообщения, которые могут показать, что происходит. Если сущность существует в базе данных, так что дублирующая вставка вызывает исключение, запрос должен ее найти. Однако код, который вы используете, кажется странным, например, внедрение entityManagerFactory вместо непосредственного внедрения EntityManager и использование запроса по идентификатору внутри транзакции вместо использования em.find (Eom.classs, projectName) вне транзакции.   -  person Chris    schedule 27.03.2014
comment
Спасибо большое, через лог я узнал, что происходит.   -  person i-developer    schedule 27.03.2014


Ответы (1)


Если вы хотите, чтобы они были доступны, это означает, что вы хотите, чтобы все операции в кеше попадали в БД. Для этого позвоните EntityManager.flush().

person Andrei I    schedule 27.03.2014