我想在 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/