【问题标题】:Deadlock in ORM when using OpenJPA使用 OpenJPA 时 ORM 中的死锁
【发布时间】:2012-10-23 12:54:56
【问题描述】:

在使用Soap UI 执行负载测试时遇到死锁,每个线程运行 10 个线程向我的 Web 服务发出 10 个请求,该服务调用 OpenJPA 实体管理器的 persits 方法。

然后我执行单个请求,一切都很好,但在多线程环境中它最终会出现死锁。

我得到的错误是:

Deadlock found when trying to get lock; try restarting transaction {prepstmnt 12796448 UPDATE Assessment SET dateCompleted = ? WHERE id = ? [params=?, ?]} [code=1213, state=40001]

由于死锁而崩溃的方法是这样的:

@Override
public AssessmentKey update(AssessmentKey assessmentKey) {
    OpenJPAEntityManager openJpaEntityMgr = OpenJPAPersistence.cast(entityManager);
    for (Assessment assessment : assessmentKey.getAssessments()) {
        if (!entityManager.contains(assessment) && !openJpaEntityMgr.isDetached(assessment)) {
            LOGGER.debug("Persisting {}", assessment);
            entityManager.persist(assessment);
        }
    }
    return entityManager.merge(assessmentKey);
}

Assessment是OpenJPA的一个实体,它只是一个包含JPA注解的普通实体。 如果您需要它的代码,请索取。

我了解死锁是如何发生的,here 中提到了如何解决它们。但是如何在 ORM 中解决它们我找不到答案。

我的persistence.xml 文件如下所示:

<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="com.groupgti.esb.online.tests">
        <provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
        <class>com.groupgti.esb.assessments.model.jpaimpl.Assessment</class>
        <exclude-unlisted-classes>true</exclude-unlisted-classes>
        <validation-mode>NONE</validation-mode>
        <properties>
            <property name="openjpa.Log" value="slf4j"/>
            <property name="openjpa.DataCache" value="false"/>
            <property name="openjpa.ReadLockLevel" value="none"/>
            <property name="openjpa.WriteLockLevel" value="pessimistic-write"/>
            <property name="openjpa.LockTimeout" value="10000"/>
            <property name="openjpa.RuntimeUnenhancedClasses" value="unsupported"/>
        </properties>
    </persistence-unit>
</persistence>

整个应用程序使用Spring,并且在其中完成事务的类标记为@Transactional。 ORM中如何解决这个死锁问题?

编辑:

AssessmentKeyAssessment 有关系:

@OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, mappedBy = "assessmentKey")
private List<Assessment> assessments = new ArrayList<Assessment>();

而在Assessment AssessmentKey 看起来像这样:

@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE})
@Index
@Column(nullable = false)
@ForeignKey
private AssessmentKey assessmentKey;

【问题讨论】:

  • @Could you post O/R AssessmentKey Assessment 的关系?

标签: java jpa orm deadlock openjpa


【解决方案1】:

AssessmentKeyAssessmentOneToMany双向关系。OneToManyManyToOne注解都有CascadeType.PERSIST等。

要点是:

EntityManager 持续存在Assessment 时,AssessmentKey 也会持续存在。您应该需要再次持久化或合并AssessmentKey

让我建议 OR Mapping 如下:

AssessmentKey.java

@OneToMany(fetch = FetchType.EAGER, cascade = {CascadeType.PERSIST, CascadeType.MERGE, CascadeType.REMOVE}, 
           mappedBy = "assessmentKey", orphanRemoval=true)
private List<Assessment> assessments;

评估.java

@ManyToOne(fetch = FetchType.EAGER, cascade = {CascadeType.REFRESH})
@JoinColumn(name = "ASSESSMENT_ID", referencedColumnName = "ID")
private AssessmentKey assessmentKey;

数据库操作

@Override
public AssessmentKey update(AssessmentKey assessmentKey) {
    OpenJPAEntityManager openJpaEntityMgr = OpenJPAPersistence.cast(entityManager);
    // there may be your operation
    return entityManager.merge(assessmentKey);
}

我假设,当前AssessmentKey 对象的Assessment 值可能如下

On System                               |   In Existing Database
ID      Description                     |   ID      Descrition
1001    AAA         => No Changes       |   1001    AAA
1002    BBB         => Need to update   |   1002    BB
null    DDD         => Need to add      |   1003    CCC     => need to remove.

当 EntityManager 合并 AssessmentKey 时,EntityManager 将完成我在上述数据结构中提到的 Assessment 的所有过程。

注意:确保orphanRemoval=trueOneToMany 注释中。

【讨论】:

    猜你喜欢
    • 2015-03-27
    • 1970-01-01
    • 2021-01-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-18
    • 2023-04-09
    相关资源
    最近更新 更多