2013-10-18 39 views
3

釋放的Blob資源我有使用EJB 3.0和Hibernate在JBoss 4.2.3 AS運行和應用由EJB控制的交易。休眠和Postgres大型對象 - 在實體finalize()方法

我正面臨一個問題,即有關Postgres日誌中有關「大錯誤:無效大對象描述符:0」之類的大對象的幾條消息,有時還會出現「錯誤:大對象488450不存在」的錯誤。結果是在應用程序中一切正常,但有時(並非總是)Postgres在hibernate提交後(在主EJB中的所有代碼被調用方法執行之後)都無法提交事務。

我調查的遺留代碼,發現所有實體的超表示在數據庫中的文件存儲。在這個類中,文件由Blob屬性表示,並由getBinaryStream()方法使用。我發現了什麼奇怪的是什麼,是在這個類的finalize()方法波紋管:

@Lob 
@Basic(fetch = FetchType.LAZY) 
@Column(name = "BIN_CONTENT", nullable = true, updatable = true) 
protected Blob content; 

@Override 
protected void finalize() throws Throwable { 
    if (this.content != null) { 
     try { 
      IOUtils.closeQuietly(this.content.getBinaryStream()); 
     } catch (Exception e) { 
      logger.severe("Error finalizing Blob stream"); 
     } 
     try { 
      this.content.free(); 
     } catch (AbstractMethodError e) { 
     } catch (SQLFeatureNotSupportedException e) { 
     } catch (UnsupportedOperationException e) { 
     } catch (Throwable e) { 
      logger.severe("Error finalizing Blob stream"); 
     } 
     this.content = null; 
    } 
    super.finalize(); 
} 

後我評論此代碼一切似乎很好地工作。問題是: 這是必要的嗎?我想了解由於執行導致數據庫端錯誤的代碼而導致的內部情況。

回答

1

您提供的代碼有幾個問題。

第一個問題是finalize()定時。

java.sql.Blob實現依賴於jdbc驅動程序,通常實現類只存儲blob的標識符,並且訪問內容時(例如使用getBinaryStream())將執行另一個數據庫調用。這意味着在調用getBinaryStream()時,用於獲取blob的連接應該仍然打開。 但是當調用finalize時,JVM不會提供任何擔保,因此在finalize中訪問Blob是不正確的。

我不確定PostgreSQL jdbc驅動程序是否將這個邏輯用於blob,但我確信java.sql.Array實現具有此限制(即連接關閉後無法調用數組方法)。

第二個問題是,雖然blob映射被定義爲懶惰,即使客戶端沒有使用它blob字段將始終由finalize()加載。

一般是客戶的責任,用斑點時執行清理。該模式對於使用的BLOB是:

try { 
    blob = entity.getContent(); 
    // ... use blob 
} finally { 
    // ... do blob cleanup 
}