[英]How to handle transactions & persistence-context in Java EE correctly?
我目前正在重構涉及Glassfish 4.0的更大的Java EE項目。 Eclipse-Link 2.5用作JPA提供程序,沒有Web界面,只有Java SE客戶端通過JNDI查找直接連接到EJB外觀。 該應用程序可以長時間正常運行,但是在3-4周后,我們總是會出現堆溢出異常 。
我決定在溢出事件發生時分析堆內存。 這是按包排序的堆的快照:
突出顯示的軟件包主要與數據庫連接有關...因此,我得出結論,如果事務/數據庫連接/持久性上下文未正確發布,肯定存在問題。 順便說一句,包ch.lawsuite.model.dao包含我們的域模型,即以@Entity注釋的實體類。 這些實例可能是由實體管理器(持久性上下文)構建的,但是這些實體類和JPA類保留了約1.5 GB,盡管此時原始數據庫的大小約為3 MB。
接下來,我將簡要介紹我們的應用程序的體系結構。 這是我們的persistence.xml的一部分:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" ... [abbreviated]">
<persistence-unit name="LawSuiteEE-ejbPU" transaction-type="JTA">
<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
<jta-data-source>jdbc/H2_DS</jta-data-source>
[abbreviated - list of all @Entity classes - abbreviated]
</persistence-unit>
</persistence>
如您所見,我們正在使用JTA(Java事務API)-但可能不是正確的方法。 這是我們在EJB模塊中用於從客戶端訪問應用程序服務器后面的數據庫的典型外觀之一的剖視圖:
@Stateless
@DeclareRoles("User")
public class AddressFacade extends AbstractFacade implements AddressFacadeLocal {
@PersistenceContext(unitName = "LawSuiteEE-ejbPU")
private EntityManager em;
@Override
@RolesAllowed("User")
public Address create(Address address) {
address= em.merge(address);
em.persist(address);
em.flush();
em.refresh(address);
return address;
}
@Override
@RolesAllowed("User")
public Address queryById(String id) {
TypedQuery<Address > query = em.createQuery("SELECT a FROM Address a WHERE a.id = '"+id+"'", Address.class);
return query.getSingleResult();
}
}
基本上,我們只希望在所有無狀態會話Bean之間共享一個持久性上下文。 或者,也可以在外觀上的每個方法調用之后構造/破壞持久性上下文。 應用程序管理的持久性上下文與容器管理的持久性上下文?
一些建議是高度贊賞的:-)!
以下是一些觀察結果:
在您的查找方法中,您調用.getSingleResult()-這可能引發NoSuchResultException-並且由於您的方法未將其聲明為throws子句的一部分,因此將其保留為方法使用者的隱性責任。 人們為此使用了幾種模式,而沒有爭論他們的優點,因為它主要歸結為樣式問題,我喜歡做以下事情:
@Nullable @Override @RolesAllowed("User") public Address queryById(String id) { Address address; TypedQuery<Address > query = em.createQuery("SELECT a FROM Address a WHERE a.id = '"+id+"'", Address.class); query.setParameter("id", id); try { address = query.getSingleResult(); }catch(NoSuchResultException nrex) { address = null; } return address; }
使用@Nullable批注可以使編譯器,您的IDE和客戶端清楚地知道,如果具有給定ID的數據庫中不存在地址,則此方法可能返回null。
就堆空間問題而言,您將不得不做更多的調查,以了解對這些類的引用所持有的內容,以了解所發生的情況。 您的應用程序代碼中可能存在泄漏。 我不知道您使用什么IDE /工具,但是Intellij IDEA的最新v14 EAP將在調試器中向您顯示所有保留對特定對象的引用的對象。 我確信其他性能分析工具也可以做到這一點。 同樣,您的JPA提供程序將緩存實體。 Eclipselink具有L1和L2高速緩存。 您可以控制要緩存的實體-全部,無,某些等等。還可以從緩存中手動逐出。 其中一些可能是緩存消耗,或者您的代碼可能在某處泄漏。 這里有一些文檔[1]。
[1] -http://wiki.eclipse.org/EclipseLink/Examples/JPA/Caching
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.