【问题标题】:Aren't multiple transactions supposed to concur with em.getTransaction()?多个事务不应该与 em.getTransaction() 一致吗?
【发布时间】:2011-04-29 11:47:27
【问题描述】:

当我执行时:

public void beginTransaction() {
    em.getTransaction().begin();
}

在以相同方式启动活动事务后,我得到以下异常:

Exception Description: Transaction is currently active
java.lang.IllegalStateException: 
Exception Description: Transaction is currently active
        at org.eclipse.persistence.internal.jpa.transaction.EntityTransactionImpl.begin(EntityTransactionImpl.java:45)
        at com.mysimpatico.memoplatform.persistence.Database.beginTransaction(Database.java:44)
        at com.mysimpatico.memoplatform.persistence.tests.PersistenceTest.setUp(PersistenceTest.java:39)

底层 DBMS 是嵌入式 apache derby,据我所知,它不支持来自不同 JVMS 的多个连接,但支持并发事务。Documentation

此测试代码失败:

public <Entity> int getNo(final Class<Entity> entityClass) {
    final CriteriaBuilder qb = em.getCriteriaBuilder();
    final CriteriaQuery<Long> cq = qb.createQuery(Long.class);
    cq.select(qb.count(cq.from(entityClass)));
    final int ret = em.createQuery(cq).getSingleResult().intValue();
    return ret;
}

protected void insertWords(final List<String[]> expressionDefTriples, MUser usr, final MeaningsDatabase mengsDB) throws Exception {
    for (String[] expressionDefTriple : expressionDefTriples) {
        mengsDB.persistSynonyms(MeaningsDatabase.toEnumMap(expressionDefTriple, usr));
        testSynonymsPersistance(expressionDefTriple,mengsDB);
    }
}

protected void testSynonymsPersistance(final String[] expDefTriple, final MeaningsDatabase mengsDB) {
    final Expression exp = mengsDB.get(Expression.class, expDefTriple[0]);
    testGender(exp, expDefTriple[2]);
    final Expression def = mengsDB.get(Expression.class, expDefTriple[1]);
    assertNotNull(def);
    assertTrue(exp.getMengs().size() > 0);
    assertTrue(def.getMengs().size() > 0);
    assertTrue(mengsDB.getNo(Meaning.class) > 0); //fails here
}

public void persistSynonyms(final EnumMap<Input, MemoEntity> input) throws MultipleMengsException {
    final Expression def = extractExp(input, Input.definition);
    final Expression exp = extractExp(input, Input.expression);
    final MUser usr = extractUsr(input);

    beginTransaction();
    final Meaning meng = persistMeng(exp, usr, def);
    commitTransaction();
    signalContentAvailability();
    logInsertion(meng, exp, def);
}

基本上我在同一个 em 中启动并提交了一个事务,但是当我使用同一个 em 执行 getNo() 方法时,它找不到前一个提交的内容。我看不出问题出在哪里。显然存在问题,因为像 em.find(..) 这样的“本地”代码会找到已提交的更改,但不能找到条件查询。

【问题讨论】:

    标签: java transactions jpa-2.0 eclipselink derby


    【解决方案1】:

    EntityManager#getTransaction()实际上返回the 当前resource local transaction并且当事务已经处于活动状态时你不能调用EntityTransaction#begin()

    /**
    * Start a resource transaction.
    * @throws IllegalStateException if isActive() is true
    */
    public void begin();
    

    您可以按照EntityManager#getTransaction() 的 javadoc 中的提示创建串行本地事务:

    /**
     * Return the resource-level <code>EntityTransaction</code> object.
     * The <code>EntityTransaction</code> instance may be used serially to
     * begin and commit multiple transactions.
     * @return EntityTransaction instance
     * @throws IllegalStateException if invoked on a JTA
     *         entity manager
     */
    public EntityTransaction getTransaction();
    

    总而言之,JPA(和 JTA)不支持nested transactions

    参考文献

    【讨论】:

    • 所以JPA不支持并发事务,只支持事务的串行执行。我理解正确吗?如果在我的应用程序中是这样,我应该锁定事务以保证串行执行。
    • @simpatico JPA 确实支持并发事务。但是您尝试做的是事务嵌套,这是不受支持的。
    • 但是我该如何进行多笔交易呢?多个 em?
    • @simpatico 如果你真的需要,可以。
    • 我已在问题中添加了后续代码。这还是事务嵌套吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-07-04
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-02-07
    相关资源
    最近更新 更多