您似乎覺得對JPA上下文中加載的實體的更改會自動提交,除非該實體已分離。這是而不是,實際上它顯然是如何工作的。但是,即使您修改附加實體並刷新,或者合併了分離的實體,也可以確保其他事務永遠不會看到更改。
它是無害的 - 而且往往一致性是一個好主意 - 執行只讀操作,當這麼久有交易開放只要你不把它開得太久 。如果你想保證沒有數據被寫入,並且你正在使用JTA,只需使用SessionContext
上的setRollbackOnly()
來確定它。對於手動JPA事務管理,請確保您在完成後致電EntityTransaction
上的rollback()
,而不是提交。
個人而言,我會建議你「getLob」方法使用一個新的事務,並回滾在方法結束。如果您的數據庫不支持嵌套事務(很少做),這通常會導致從池中獲取新連接以執行此項工作。
如果你使用JTA和容器管理的事務,請嘗試:
@Stateless
@TransactionManagement(TransactionManagementType.CONTAINER)
public class LobTest {
@PersistenceContext
private EntityManager em;
@Resource
private SessionContext sctx;
@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public byte[] getLob() {
// Get your LOB content by fetching a new copy of the entity from the DB
// by ID, avoiding the need to split the LOB out. Note that you lose
// tx consistency guarantees between the LOB and the rest of the entity by
// doing this.
// then after loading the LOB:
sctx.setRollbackOnly();
}
}
另外,如果你不介意的錯誤讀取LOB中止任何周圍的事務,使用TransactionAttributeType.REQUIRES
代替REQUIRES_NEW
和Don」 t setRollbackOnly()
。你不能改變任何東西,所以沒有什麼會被提交。如果尚未打開,它將打開一個新事務,否則將加入現有事務,以便您可以一致地讀取LOB。唯一的缺點是一些數據庫錯誤會中止整個JTA事務。
如果您使用用戶管理的事務與非JTA環境中,僅僅獲得一個新的EntityManager,得到一個EntityTransaction,使用em.find(...)
加載包含實體LOB的新副本等
。好的,所以在大多數數據庫中都有一些不需要事務處理的對象類型,比如PostgreSQL SEQUENCE
和相關的SERIAL
僞類型,諮詢鎖等等,即使回滾的事務也會受到這種類型的影響。事務也可以「鎖定」數據庫,從而鎖定可能阻止其他操作的資源。對於實際的數據,這是安全的。
。如果可以的話,避免讓tx保持打開狀態的時間超過幾秒鐘,因爲長時間運行的事務會導致某些數據庫出現性能問題,並且會阻塞連接池。避免在「用戶的思考時間」內保持交易 - 當你等待用戶做某件事時 - 他們可能會做白日夢,午餐,度假或月球......讓你的窮人數據庫和連接池等待他們的回報。
這是一個非常類似於我們想過的解決方案(添加一個讀取Lob內容的事務方法,以便我們可以使用它)。 我認爲如果沒有奇蹟發生,我們會爲之努力,因爲它是我們能找到的最好的。 – 2012-07-25 08:05:33
@XavierPortebois可惜的是PgJDBC無法讓你獲得整個LOB的更透明,從而關注幕後的事務管理。也許你應該看看PgJDBC的來源?畢竟它是開源的,你可能會加強它以適應你的需求。 – 2012-07-25 13:53:43
哇。在寫這篇文章的時候,我發現JTA bean管理的事務沒有相同的'REQUIRES_NEW'。他們不能暫停和恢復交易。如果您希望您使用*的功能來使用容器管理的事務。 – 2012-07-26 00:00:27