2012-12-06 124 views
2

在我們的一個項目中,用戶可以將文件附加到他的帳戶。我們將這些文件存儲在MS-SQL數據庫中。因此,我們有如下一段代碼:EntityManager內存消耗

@Entity 
public class File extends AbstractEntity { 

    @Lob 
    @Basic 
    private byte[] data; 

    @Nullable 
    public byte[] getData() { 
     return data; 
    } 

    public void setData(byte[] data) { 
     this.data = data; 
    } 

    public File() { 
    } 

    public File(byte[] data) { 
     this.data = data; 
    } 
} 

public class SomeBean { 

    @PersistenceContext 
    protected EntityManager em; 

    public Long uploadFile(@NotNull byte[] data) { 
     final PhysicalFile physicalFile = new PhysicalFile(); 
     physicalFile.setData(data); 
     em.persist(physicalFile); 
     return physicalFile.getId(); 
    } 
} 

,一切都不錯,漂亮,之前我們嘗試上傳40 MB的文件,並得到了java.lang.RuntimeException: javax.transaction.RollbackException: [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] [com.arjuna.ats.internal.jta.transaction.arjunacore.commitwhenaborted] Can't commit because the transaction is in aborted state,這是在uploadFile()方法內外因java.lang.OutOfMemoryError: Java heap space

我做了一個堆轉儲,並在VisualVM中查看它。
Heap Dump

400多MB的char[]和100 + MB的byte[]。在開始,我們的應用程序(包括JBoss)正在使用大約60-65 MB的堆。所以,問題是,爲什麼EntityManager像瘋了一樣消耗堆內存?

回答

1

我對你的問題漠不關心,如下。

  • 所有通過一個EntityManager該負載/堅持實體停留在內存中,直到您明確地從中分離實體(通過EntityManager.detach()或EntityManager.clear()或EntityManager.close())。所以最好有短暫的EntityManagers。

  • 只要在業務邏輯中發生RuntimeException,EntityManager保持打開狀態!你總是希望避免這種 的代碼。你能想到的創建和關閉的EntityManager作爲 的如下:

    public Customer getBestCustomerOfMonth() { 
    EntityManagerFactory emf = ... ; 
    EntityManager em = emf.createEntityManager(); 
    // business logic 
    em.close(); 
    } 
    
  • 您可以巢關閉的EntityManager em.close行();一個最終 塊使用事務時,企業應用服務器 之外,因爲你必須在 關閉(提交或回滾)事務您EntityMangers做同樣的方式

  • 內。爲了使這些資源 (兩者的EntityManager和相關交易)被關閉,你會 需要做的嵌套的追加等級和寫類似這樣的代碼 :

     public Customer updateCustomer(Customer cust) { 
    
         EntityManagerFactory emf = ... ; EntityManager em = 
        emf.createEntityManager(); try { 
        EntityTransaction t = em.getTransaction(); 
        try { 
         t.begin(); 
         // business logic to update the customer 
         em.merge(cust); 
         t.commit(); 
        } finally { 
         if (t.isActive()) t.rollback(); 
        } } finally { 
        em.close(); 
         }  
        } 
    

您可能認爲這個嵌套結構可能看起來有點亂,但在交易之前確實需要它。