首页 > 解决方案 > 如何处理 INSERT 并发问题,我在 glassfish 4.1 中使用 eclipselink jpa 和 mysql?

问题描述

我的应用程序中有 2 个事务想要更新相同实体的子集。但是其中一些实体不在数据库中,因此两个线程都创建相同的实体并尝试提交它。导致数据库主键重复条目。我该如何处理?

例如事务 1 想要更新实体 A、B、C、D、E、F 事务 2 想要更新实体 D、E、F、G、H、I 我的数据库只有实体 A、C、E、G 和我

因此事务 1 和 2 尝试创建实体 D。第二个线程未能提交,因为 D 是主键并且现在已经存在。

我尝试过使用 pessimistic_write,但这对尚不存在的记录没有帮助。

我尝试将我的 persist() 调用包装在 try catch 中,但似乎异常是在 JPA 内部抛出的,而我的应用程序永远不会看到它。

大多数 google 搜索返回有关锁定现有记录的示例,如果它们碰巧提到并发插入,这似乎超出了本文的范围。

有些文章说我应该使用数据库生成的唯一 ID,这在我的实例中不起作用。或者我应该在我的实体中使用一个版本,但我的实体模型再次根据其先前的值提高了其准确性,实体的值不是孤立的,而是依赖于先前的事务。

我考虑过预填充数据库,但可能有超过十亿个可能的有效实体键,虽然我只处理一组大约 20,000 个键,但在事务进入之前我不知道它们是什么。

这是我的带有 try catch 包装器的持久代码,我从来没有从我的应用程序中看到消息“插入持久性冲突”,只是 JPA 堆栈跟踪。

if (cellmu == null)
{
    CellMUEntity cellmuNew = new CellMUEntity();
    cellmuNew.setId(cellOuter);
    cellmuNew.setDistribution(mus);
    try {
        em.persist(cellmuNew);
    } catch (Exception e) {
        System.out.println("INSERT Persistence collision, " +e.getClass().getName() +" read and refine (" + cellOuter+")" );
        cellmuNew = em.find(CellMUEntity.class,cellOuter,LockModeType.PESSIMISTIC_WRITE);
        cellmuNew.setDistribution(cellmuNew.getDistribution().refine(mus));
        em.merge(cellmuNew);
    }
}

这是来自 jpa 的堆栈跟踪的一部分...

[2019-05-01T21:07:07.654+1000] [glassfish 4.1] [WARNING] [jts.unexpected_error_occurred_in_after_completion] [javax.enterprise.system.core.transaction.com.sun.jts.jta] [tid: _ThreadID=70 _ThreadName=p: thread-pool-1; w: 2] [timeMillis: 1556708827654] [levelValue: 900] [[
  JTS5054: Unexpected error occurred in after completion
Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.1.v20150605-31e8258): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '6ad63bd4' for key 'PRIMARY'
Error Code: 1062
Call: INSERT INTO mucell (cellid, mu_high, mu_low) VALUES (?, ?, ?)
    bind => [3 parameters bound]
Query: InsertObjectQuery((face=3, pos=ad63bd400000000, level=13):[0.0, 47499.492305012])
    at org.eclipse.persistence.exceptions.DatabaseException.sqlException(DatabaseException.java:331)

标签: jpaeclipselinksql-insertdatabase-concurrency

解决方案


推荐阅读