【问题标题】:Spring managed transactions, EclipseLink JPA, custom isolation levelSpring 托管事务、EclipseLink JPA、自定义隔离级别
【发布时间】:2014-06-18 19:52:25
【问题描述】:

我怀疑这件事很尴尬,我做错了很糟糕,但请多多包涵。

我有一个带有 Spring 管理事务的 Spring 应用程序。 它使用 EclipseLink JPA。 我有一个方法,它执行findByNativeQuery(),后跟merge()。我需要在真正的 SERIAL 事务隔离级别中发生这种情况。 我尝试添加 @Transactional(isolation=Isolation.SERIALIZABLE)

这不起作用,因为org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect#beginTransaction 不支持任何事务隔离级别,但默认。 因此,我尝试进入 ElcipseLink 的 UnitOfWork 内部并开始/提交我自己的事务,但随后出现错误:

"java.lang.IllegalStateException : Not allowed to create transaction on shared EntityManager - use Spring transactions or EJB CMT instead

这当然是有道理的......但是我该怎么办??

【问题讨论】:

  • 看看this。我自己没有尝试过,但看起来是个不错的起点。
  • 我认为 JPA 不支持自定义隔离级别。这是 JPA 的限制,而不是 Spring。它可能需要实现自定义 JpaDialect

标签: java spring jpa transactions eclipselink


【解决方案1】:

我已经对此进行了尝试,但我并不完全确定解决方案。我从this blog 获取了代码,并将其改编为EclipseLink。代码如下:

package com.byteslounge.spring.tx.dialect;

import java.sql.SQLException;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

import org.eclipse.persistence.sessions.UnitOfWork;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionException;

public class CustomEclipseLinkJpaDialect extends EclipseLinkJpaDialect {

    private static final long serialVersionUID = 1L;

    private boolean lazyDatabaseTransaction = false;

    @Override
    public void setLazyDatabaseTransaction(boolean lazyDatabaseTransaction) {
        this.lazyDatabaseTransaction = lazyDatabaseTransaction;
    }

    @Override
    public Object beginTransaction(final EntityManager entityManager,
            final TransactionDefinition definition)
            throws PersistenceException, SQLException, TransactionException {

        UnitOfWork uow = (UnitOfWork) getSession(entityManager);
        uow.getLogin().setTransactionIsolation(definition.getIsolationLevel());

        entityManager.getTransaction().begin();
        if (!definition.isReadOnly() && !lazyDatabaseTransaction) {
            uow.beginEarlyTransaction();
        }

        return null;
    }
}

我看到在事务启动时记录了 SERIALIZABLE 隔离,但这需要正确测试以确认它有效。

【讨论】:

  • 我已经调试了我的代码并进入了JpaTransactionManager.doBegin() 方法并检查了正在获取的ConnectionHandle 以寻找实际的MySQL com.mysql.jdbc.JDBC4Connection 实例。实际使用的实际连接确实使用了为该方法设置的隔离级别 (javax.sql.Connection.TRANSACTION_SERIALIZABLE)。
  • 我们还没有时间测试它,但我想我会给予赏金,因为这是唯一需要付出巨大努力的答案。未来的读者要小心——这个公认的答案尚未经过正确性评估。
  • 我试了一下。请教育我.. 它是否适用,事务定义为 PROPAGATION_REQUIRED 和 ISOLATION_SERIALIZABLE 将使所有事务从另一个线程创建,WAIT 如果已经有一个具有相同定义的事务正在运行?那么如果我想实现它需要调整什么?
  • 在 Spring 3.2.13 中为 PROPAGATION_REQUIRED 工作。谢谢。
【解决方案2】:

在 Spring 4.1.2 中添加了对自定义隔离级别的支持到 EclipseLinkJpaDialect

【讨论】:

    【解决方案3】:

    可以参考

    "要使用 EclipseLink 实现可序列化的事务隔离,我们建议您使用隔离的客户端会话,如下所示:

    将数据库事务隔离配置为可序列化。 将对象配置为隔离(请参阅在项目级别配置缓存隔离或在描述符级别配置缓存隔离)。 使用 UnitOfWork 方法 beginTransactionEarly(请参阅工作单元方法 beginTransactionEarly)。 如果只关心可序列化的写入方面,乐观锁就足够了。”

    http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm 或通过 http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm 如果任何隔离级别满足您的要求

    【讨论】:

      猜你喜欢
      • 2016-09-11
      • 2013-05-27
      • 2015-07-21
      • 2011-03-26
      • 2011-02-24
      • 2020-06-07
      • 2011-04-24
      • 2015-10-18
      • 2011-03-19
      相关资源
      最近更新 更多