Spring managed transactions, EclipseLink JPA, custom isolation level

你。 提交于 2019-12-07 04:01:00

问题


I suspect this one is embarrassing an I am doing it wrong in a terrible way, but please bear with me.

I have a Spring application with Spring-managed transactions. It uses EclipseLink JPA. I have a method which does a findByNativeQuery() followed by a merge(). I need this to happen in a real SERIAL transaction isolation level. I tried adding @Transactional(isolation=Isolation.SERIALIZABLE)

This doesn't work because org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect#beginTransaction does not support any transaction isolation level but the default. So then I tried getting to UnitOfWork internals of ElcipseLink and starting/comitting my own transactions, but then I get an error:

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

Which of course makes sense... but what do I do??


回答1:


I've given a try to this, but I am not completely sure of the solution. I've taken the code from this blog and adapted it for EclipseLink. Here's the code:

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;
    }
}

I'm seeing the SERIALIZABLE isolation being logged when the transaction is initiated, but this needs to be tested properly to confirm it works.




回答2:


Support for custom isolation level was added in Spring 4.1.2 to EclipseLinkJpaDialect




回答3:


You can refer

"To achieve serializable transaction isolation with EclipseLink, we recommend that you use an isolated client session as follows:

Configure the database transaction isolation as serializable. Configure objects as isolated (see Configuring Cache Isolation at the Project Level or Configuring Cache Isolation at the Descriptor Level). Use the UnitOfWork method beginTransactionEarly (see Unit of Work Method beginTransactionEarly). If you are only concerned about the write aspect of serializable, optimistic locking is sufficient."

at http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm or go through http://docs.oracle.com/middleware/1212/toplink/OTLCG/cache.htm if any of isolation level meets your requirement



来源:https://stackoverflow.com/questions/24293945/spring-managed-transactions-eclipselink-jpa-custom-isolation-level

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!