2016-01-14 33 views
0

我正在使用自定義事務隔離級別在JPA EntityManager的基礎連接上使用此代碼設置JPA(EclipseLink)中的事務:更改JPA/EclipsLink EntityManager中的隔離級別後清理

// begin transaction 
entityManager.getTransaction().begin(); 

// store the old isolation level 
int isolationLevelOld = entityManager.unwrap(Connection.class).getTransactionIsolation(); 

// set the desired isolation level for this transaction 
entityManager.unwrap(Connection.class).setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); 

[...Queries...] 

// commit transaction 
entityManager.getTransaction().commit(); 

// reset isolation level to the old value (throws NullPointerException) 
entityManager.unwrap(Connection.class).setTransactionIsolation(isolationLevelOld); 

如果我嘗試在提交事務後將隔離級別重置爲舊值,則基礎連接爲空(entityManager.unwrap(Connection.class)返回null)。我很擔心,如果我只是不重置隔離級別,那麼具有不良隔離級別的連接會泄漏回池中。

更改隔離級別後,清理的正確方法是什麼?我應該在調用commit()之前做到這一點嗎?

回答

1

java.sql.Connection被返回到調用池中entityManager.getTransaction().commit();所以復位的隔離級別以後是不可能的,通過返回null連接通過的EclipseLink阻止。

保持到Connection參考規避這有可能會泄露與改變設置的連接,所以我不能接受你的答案RomanC

我結束了創建的EntityManagerFactory兩個實例。一個創建默認EntityManagers和一個使用SessionCustomizer與我期望的事務級連接與創建EntityManagers

public static class SessionCustomizer implements org.eclipse.persistence.config.SessionCustomizer { 
    @Override 
    public void customize(Session session) throws Exception { 
     DatabaseLogin databaseLogin = (DatabaseLogin) session.getDatasourceLogin(); 
     databaseLogin.setTransactionIsolation(DatabaseLogin.TRANSACTION_SERIALIZABLE); 
    } 
} 

private void init() { 
    entityManagerFactoryRegular = Persistence.createEntityManagerFactory("MyPersitenceRegular"); 
    Map<String, String> props = new HashMap<>(); 
    props.put(PersistenceUnitProperties.SESSION_CUSTOMIZER, SessionCustomizer.class.getName()); 
    entityManagerFactoryTransactionSerializable = Persistence.createEntityManagerFactory("MyPersitenceTransactionSerializable", props); 
} 

看到這裏Set Isolation level in eclipselink

然後我用我提供爲準需要連接類型EntityManagerFactory。注意:事務不能跨越多個 EntityManagerFactories

0

試試下面的代碼

Connection conn = entityManager.unwrap(Connection.class); 

conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE); 

[...Queries...] 

// commit transaction 
entityManager.getTransaction().commit(); 

conn.setTransactionIsolation(isolationLevelOld); 
+0

我檢出了Eclipselink源代碼:'java.sql.Connection'由'DatabaseAccessor'封裝,它返回到'entityManager.getTransaction()中的一個池。commit ();'。我不確定池的生命週期,如果它是EntityManager的本地,但如果不是,那意味着在調用commit之後重置事務隔離級別太遲了,因爲連接可能在其他地方重用這兩個電話。 – Twilite

+0

當然不是,但是如果從池中獲取連接,應該解決默認隔離問題,並且在啓動新事務時將使用此隔離,在某些情況下,您可以更改當前事務的隔離級別,但我認爲這不是你的情況。當你提交一個事務時,你不能再使用它了,甚至改變它的隔離級別,但是如果你關閉了一個連接,它將不會關閉與數據庫的連接,但是返回一個連接對象到池中,你也可以在關閉之前測試它確保連接有效。 –