2014-01-28 4 views
2

Я хотел бы использовать разные уровни изоляции транзакций для одного и того же контекста устойчивости в среде J2EE. Например:J2EE/JPA: контроль изоляции транзакций

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 сначала приобретает соединение с БД, оно берется из пула и немедленно заносится в текущую транзакцию XA. Впоследствии невозможно изменить транзакционную изоляцию этой транзакции DB.

Любые идеи?

+0

Вот некоторая интересная информация для вас: http://amitstechblog.wordpress.com/2011/05/31/supporting-custom-isolation-levels-with-jpa/ –

+0

@Pat B: спасибо за ссылку , В блоге обсуждается решение Hibernate/Spring. Насколько я могу судить, он не может использоваться в среде JTA (например, J2EE), поскольку транзакция начинается с реализации Datasource, а не от самого поставщика JPA. – ruediste

ответ

0

Я использую Glassfish/EclipseLink/MySQL. Решение, которое я нашел, это настроить MySQL DataSource, чтобы вернуть оболочку вокруг 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)); 
} 
} 
Смежные вопросы