Hibernate应用程序级可重复读取
介紹
在我以前的文章中,我描述了應用程序級事務如何為長時間的對話提供合適的并發控制機制。
所有實體都在Hibernate會話的上下文中加載,充當事務后寫式緩存 。
Hibernate持久性上下文可以包含給定實體的一個引用和一個引用。 一級緩存可確保會話級可重復讀取。
如果對話跨越多個請求,我們可以進行應用程序級的可重復讀取。 長時間的對話本質上是有狀態的,因此我們可以選擇分離的對象或長期的持久性上下文 。 但是,應用程序級可重復讀取需要應用程序級并發控制策略,例如樂觀鎖定。
抓住
但是這種行為有時可能被證明是出乎意料的。
如果您的Hibernate會話已經加載了給定的實體,那么任何后續的實體查詢(JPQL / HQL)都將返回完全相同的對象引用(不考慮當前加載的數據庫快照):
在此示例中,我們可以看到第一級緩存可防止覆蓋已加載的實體。 為了證明這種行為,我提出了以下測試案例:
final ExecutorService executorService = Executors.newSingleThreadExecutor();doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {Product product = new Product();product.setId(1L);product.setQuantity(7L);session.persist(product);return null;} });doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session session) {final Product product = (Product) session.get(Product.class, 1L);try {executorService.submit(new Callable<Void>() {@Overridepublic Void call() throws Exception {return doInTransaction(new TransactionCallable<Void>() {@Overridepublic Void execute(Session _session) {Product otherThreadProduct = (Product) _session.get(Product.class, 1L);assertNotSame(product, otherThreadProduct);otherThreadProduct.setQuantity(6L);return null;}});}}).get();Product reloadedProduct = (Product) session.createQuery("from Product").uniqueResult();assertEquals(7L, reloadedProduct.getQuantity());assertEquals(6L, ((Number) session.createSQLQuery("select quantity from Product where id = :id").setParameter("id", product.getId()).uniqueResult()).longValue());} catch (Exception e) {fail(e.getMessage());}return null;} });該測試案例清楚地說明了實體查詢和SQL預測之間的區別。 盡管SQL查詢投影總是加載最新的數據庫狀態,但是實體查詢結果由第一級緩存管理,以確保會話級可重復讀取。
解決方法1:如果您的用例要求重新加載最新的數據庫實體狀態,則只需刷新有問題的實體。
解決方法2:如果希望將某個實體與Hibernate一級緩存解除關聯,則可以輕松地將其退出 ,因此下一個實體查詢可以使用最新的數據庫實體值。
超越偏見
休眠是一種手段,而不是目標。 數據訪問層既需要讀取又需要寫入,而普通的JDBC和Hibernate都不是一種千篇一律的解決方案。 數據知識堆棧更適合于獲取最多的數據讀取查詢和寫入DML語句。
盡管原生SQL仍然是事實上的關系數據讀取技術,但是Hibernate在寫入數據方面表現出色。 Hibernate是一個持久性框架,您永遠不要忘記這一點。 如果計劃將更改傳播回數據庫,則加載實體是有意義的。 您不需要加載用于顯示只讀視圖的實體,在這種情況下,SQL投影是更好的選擇。
會話級可重復讀取可防止并發寫入場景中的更新丟失,因此,有充分的理由說明實體不會自動刷新。 也許我們選擇了手動刷新臟屬性 ,并且自動刷新實體可能會覆蓋同步的未決更改。
設計數據訪問模式并不是一件容易的事,值得投資堅實的集成測試基礎。為避免任何未知行為,我強烈建議您驗證所有自動生成的SQL語句,以證明其有效性和效率 。
- 代碼可在GitHub上獲得 。
翻譯自: https://www.javacodegeeks.com/2014/10/hibernate-application-level-repeatable-reads.html
總結
以上是生活随笔為你收集整理的Hibernate应用程序级可重复读取的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基金备案号查询(基金备案号)
- 下一篇: 使用PrimeFaces开发数据导出实用