Spring 管理的事务,EclipseLink JPA,自定义隔离级别。

7
我猜这件事很尴尬,我可能做错了,但请耐心等待。
我有一个使用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

当然有道理,但我该怎么办?

1
看一下这个。虽然我自己没有尝试过,但看起来是一个不错的起点。 - Andrei Stefan
我认为JPA不支持自定义隔离级别。这是JPA的限制,而不是Spring的限制。可能需要实现自定义JpaDialect。 - Chakradhar K
3个回答

6

我尝试过这个方法,但是我不完全确定解决方案。我从这篇博客中获取了代码,并对其进行了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)。 - Andrei Stefan
我们还没有时间测试它,但我想给出奖励,因为这是唯一一个付出了大量努力的答案。未来的读者请注意——这个被接受的答案尚未经过正确性评估。 - MK.
我尝试了一下,请指教。如果使用事务定义为PROPAGATION_REQUIRED和ISOLATION_SERIALIZABLE,是否会使来自另一个线程创建的所有事务<b>等待</b>,如果已经有相同定义的事务正在运行?那么,如果我想实现这个目标,需要调整什么? - Chet
对于Spring 3.2.13的PROPAGATION_REQUIRED,这对我有效。谢谢。 - Bob

3

Spring 4.1.2新增了对自定义隔离级别的支持,添加到了EclipseLinkJpaDialect中(参考链接)


0
您可以参考以下操作以实现使用 EclipseLink 的可序列化事务隔离:
1. 将数据库事务隔离级别配置为 Serializable。 2. 将对象配置为 Isolated(请参阅项目级别的缓存隔离配置或描述符级别的缓存隔离配置)。 3. 使用 UnitOfWork 方法 beginTransactionEarly(请参阅 Unit of Work Method beginTransactionEarly)。 如果您只关注 Serializable 的写方面,则乐观锁定足以满足要求。
如果您需要更多信息,请查看链接:http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm 或浏览网站 http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm,以了解是否有满足您要求的隔离级别。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接