java - J2EE/JPA : Controlling Transaction Isolation

标签 java jakarta-ee jpa transactions glassfish

我想在 J2EE 环境中对相同的 Persistence Context 使用不同的事务隔离级别。例如:

UserTransaction ut=...;
EntityManagerFactory emf=...;
EntityManager em=emf.createEntityManager;

ut.begin();
em.joinTransaction(); => use RepeatableRead isolation here
...
ut.commit();

ut.begin();
em.joinTransaction(); => use Serializable isolation here
...
ut.commit();

我找不到实现该目标的方法。当 EM 第一次获取 DB 连接时,它会从池中取出并立即加入当前的 XA 事务。之后就不可能再更改该数据库事务的事务隔离。

有什么想法吗?

最佳答案

我正在使用 Glassfish/EclipseLink/MySQL。我找到的解决方案是自定义 MySQL 数据源以返回围绕 XAResource 的包装器,它在启动 XA 事务之前设置事务隔离。这样,可以在开始事务之前设置所需的事务隔离。

public class CustomDataSource extends MysqlXADataSource {

private static ThreadLocal<Integer> isolation=new ThreadLocal<Integer>(){
    protected Integer initialValue() {
        return Connection.TRANSACTION_REPEATABLE_READ;
    };
};

public static void setTransactionIsolation(int i){
    isolation.set(i);
}

private static class XAConnectionWrapper implements XAConnection {

    private XAConnection delegate;

    public XAConnectionWrapper(XAConnection delegate) {
        this.delegate = delegate;
    }

    ... delegate methods

    @Override
    public XAResource getXAResource() throws SQLException {
        return new XAResourceWrapper(delegate.getXAResource());
    }

    @Override
    public boolean equals(Object obj) {
        return delegate.equals(obj);
    }

    @Override
    public int hashCode() {
        return delegate.hashCode();
    }
}

private static class XAResourceWrapper implements XAResource {
    private XAResource delegate;
    private Field field;

    ... delegate methods ...

    public void start(Xid xid, int flags) throws XAException {
        try {
            ConnectionImpl connection = (ConnectionImpl) field
                    .get(delegate);
            connection
                    .setTransactionIsolation(isolation.get());
        } catch (IllegalArgumentException | IllegalAccessException
                | SQLException e) {
            throw new RuntimeException(e);
        }
        delegate.start(xid, flags);
    }

    public XAResourceWrapper(XAResource delegate) {
        try {
            field = MysqlXAConnection.class
                    .getDeclaredField("underlyingConnection");
            field.setAccessible(true);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (SecurityException e) {
            throw new RuntimeException(e);
        }
        this.delegate = delegate;
    }

    @Override
    public boolean equals(Object obj) {
        return delegate.equals(obj);
    }

    @Override
    public int hashCode() {
        return delegate.hashCode();
    }
}

@Override
public XAConnection getXAConnection() throws SQLException {
    XAConnection conn = super.getXAConnection();

    return new XAConnectionWrapper(conn);
}

@Override
public XAConnection getXAConnection(String u, String p) throws SQLException {
    return new XAConnectionWrapper(super.getXAConnection(u, p));
}
}

关于java - J2EE/JPA : Controlling Transaction Isolation,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21415177/

相关文章:

java - Android:将 android.net.Uri 对象保存到数据库

java - 使用 Selenium IE webdriver 和 JAVA 识别特定字符串后面的文本

java - 我们能知道启动当前 Activity 的类名吗?

java - 从 Web 应用程序中发送/接收电子邮件?

java - 如何优化activemq

java - 在 Rhino 中,我可以枚举可用的 Java 包列表吗?如何?

Web 项目中的 Java EE 模块依赖项?

hibernate 错误 java.lang.NoSuchMethodError

mysql - SpringBoot JPA MappedBy 引用一个未知的目标实体属性

java - JPA nativeQuery 返回缓存的 resultList