【问题标题】:Eclipselink with JTA does not find the newly inserted entity and throws Duplicate Key Exception带有 JTA 的 Eclipselink 找不到新插入的实体并抛出 Duplicate Key Exception
【发布时间】:2014-05-05 10:12:13
【问题描述】:

我想在 Glassfish 3.1.2 应用服务器上使用 JTA(容器管理事务)和 EclipseLink 将 JPA 实体列表持久化到 MySQL 数据库。

该列表作为消息一个接一个地通过 JMS,每次收到消息时,使用无状态外观,我正在查看该实体是否存在,如果是,那么我从同一个外观调用更新,否则插入方法。

然而,在插入一个实体之后,如果我从消息中得到相同的结果,exists 方法不会检索新插入的,因此门面会尝试再次插入它并导致重复键异常。

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

任何帮助表示赞赏...

我的实体

包 clearquest.crud.domain; 导入 java.io.Serializable;

导入 javax.ejb.Lock; 导入 javax.ejb.LockType; 导入 javax.persistence.*;

导入 java.util.List;

@实体 @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 实现可序列化 { 私有静态最终长序列版本UID = 1L; 私有字符串项目名称; 私有列表缺陷;

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; 导入 java.io.Serializable;

导入 javax.ejb.Lock; 导入 javax.ejb.LockType; 导入 javax.persistence.*;

导入 java.util.List;

@无状态 @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; 导入 java.io.Serializable;

导入 javax.ejb.Lock; 导入 javax.ejb.LockType; 导入 javax.persistence.*;

导入 java.util.List;

@无状态 @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());
    }
}

按照克里斯所说的去做后,我发现了发生了什么。这是一种 Race Condition。

[#|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 -- 插入 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 -- 插入 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:键“PRIMARY”的重复条目“PRJ-00359” 错误代码:1062 调用:INSERT INTO eom (PROJECTNAME) VALUES (?) bind => [1个参数绑定]

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

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

【问题讨论】:

  • 将 eclipselink 日志设置为精细或精细,以查看可能显示正在发生的事情的事务、SQL 和其他消息。如果实体存在于数据库中以致重复插入导致异常,则查询应找到它。不过,您使用的代码似乎很奇怪,例如注入 entityManagerFactory 而不是直接注入 EntityManager,并在事务中使用对 id 的查询而不是在事务外使用 em.find(Eom.classs, projectName)。跨度>
  • 非常感谢,通过日志我发现了发生了什么。

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


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-11-21
    • 2012-10-05
    • 1970-01-01
    • 1970-01-01
    • 2012-06-12
    • 1970-01-01
    • 2018-04-07
    相关资源
    最近更新 更多