带有JTA的Eclipselink找不到新插入的实体并抛出Duplicate Key Exception

时间:2014-03-26 18:59:59

标签: java-ee jpa eclipselink glassfish-3 jta

我想在Glassfish 3.1.2应用服务器上使用带有EclipseLink的JTA(容器管理事务)将JPA实体列表保存到MySQL数据库。

列表将逐一传递给JMS作为消息,每次消息到来时,使用无状态门面,我正在查看此实体是否存在,如果是,则比我从同一门面调用更新,否则插入方法

但是,在插入一个实体之后,如果我从消息中得到相同的内容,则exists方法不会检索新插入的内容,因此外观会尝试再次插入它,并产生重复的键异常。

如何告诉EntityManager(或其他人:-))新插入的实体应该立即可用?

任何帮助表示赞赏...

我的实体

package clearquest.crud.domain; import java.io.Serializable;

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

import java.util.List;

@Entity @table(名称=" EOM&#34) @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实现Serializable {     private static final long serialVersionUID = 1L;     private String projectname;     私人清单缺陷;

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

package clearquest.crud.domain; import java.io.Serializable;

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

import java.util.List;

@Stateless @辛格尔顿 公共课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;
    }
}

}

和FACADE

package clearquest.crud.domain; import java.io.Serializable;

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

import java.util.List;

@Stateless @辛格尔顿 公共类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 | INFO | glassfish3.1.2 | com.generali.tools.myemi.components.clearquest.crud.facade.DefectListFacade | _ThreadID = 2605; _ThreadName = Thread- 10; | EOM - INSERTED PRJ-00359 |#]

[#| 2014-03-27T11:22:39.051 + 0100 | INFO | glassfish3.1.2 | com.generali.tools.myemi.components.clearquest.crud.facade.DefectListFacade | _ThreadID = 2603; _ThreadName = Thread- 10; | EOM - INSERTED 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.MySQLIntegrityConstraintViolationException:重复条目&#39; PRJ-00359&#39;关键&#39; PRIMARY&#39; 错误代码:1062 调用:INSERT INTO eom(PROJECTNAME)值(?)     bind =&gt; [1参数绑定]

有两个JMS消息彼此相邻,具有相同的EOM名称(主键),并且线程号2605首先插入EOM。但是还有另一个具有编号2603的线程,它也在第一次插入之后插入相同的主键。无论如何第二个线程都不知道第一个插入。

现在问题是,如何锁定第二个插件等待第一个插件完成?

1 个答案:

答案 0 :(得分:1)

如果您希望它们可用,则意味着您希望缓存中的所有操作都能访问数据库。为此,请致电EntityManager.flush()