我正在调查使用JPA获取我的数据访问代码。我正在尝试编写业务层和数据访问层,以便它可以在Web应用程序和Java SE应用程序中工作。因此我不能使用容器管理的持久化上下文。我使用JPA的大部分内容都在容器管理环境中显示了示例。
每次我在创建服务类的新实例时都会获得EntityManagerFactory。对于每个操作(即添加,获取等),我打开一个EntityManager,启动事务执行操作,提交然后关闭EntityManager和EntityManagerFactory。我希望在Java EE环境之外有一个manged持久化上下文的好处。
不使用容器管理上下文时是否有最佳做法?是否有任何Java EE独立持久化上下文管理器?有推荐的模式吗?
谢谢,
的Al
更新
感谢eveyone提供的信息。一切都非常有用。
答案 0 :(得分:5)
我不确定这方面的最佳做法,但我花了很多时间尝试做这样的工作。
基本上你需要一些东西来构建EntityManager
。我一直用Spring来做这件事。他们的documentation对此有很大的帮助。您可以选择使用LocalEntityManagerFactoryBean,在这种情况下,标记看起来像(来自前面提到的documentation):
<bean id="myEmf" class="org.springframework.orm.jpa.LocalEntityManagerFactoryBean">
<property name="persistenceUnitName" value="myPersistenceUnit"/>
</bean>
原则上,这是不鼓励的,因为当您稍后尝试更改数据源时,它会再次困扰您。但是,我发现对于大多数特定大小的Web应用程序来说,你不太可能遇到这种限制。
然后可以通过持久性单元中的hibernate特定属性(META-INF /目录中的persistence.xml)来配置数据源:
<property name="hibernate.connection.driver_class" value="com.company.driver" />
<property name="hibernate.connection.url" value="some:jdbc@string" />
<property name="hibernate.connection.username" value="myuser" />
<property name="hibernate.connection.password" value="mypassword" />
要使用此功能,如果您尚未使用spring,则可以从应用程序上下文中获取EntityManagerFactory
的实例并从那里开始(即context.getBean("myEmf")
)。
使用LocalContainerEntityManagerFactoryBean
可以进行更多控制,这个允许您配置数据源。原则上,文档中的示例应该可以工作,但我发现当我这样做时,我必须指定Hibernate持久性提供程序。你需要一个persistence.xml,但它实际上只需要一个默认的持久性单元和非常基本的配置(也许需要识别方言,例如,如果你在oracle 10g中使用hibernate):
<bean id="emf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="myDatasource" />
<property name="persistenceProvider">
<bean class="org.hibernate.ejb.HibernatePersistence" />
</property>
</bean>
春季文档中有关于如何从Apache dbcp配置BasicDataSource
的示例,这也会为您提供连接池。
对于最佳实践,JPA在完整的应用程序服务器环境之外实际上并不容易。在尝试调整性能时会遇到各种各样的问题,您会发现自己对于JPA中无法使用的Hibernate功能垂涎三尺,而且您的查询可能最终并不严格符合JPA规范。如果您没有使用容器管理,那么直接使用Hibernate API可能会更容易和更安全。
答案 1 :(得分:4)
目前,每当我创建服务类的新实例时,我都会获得EntityManagerFactory。对于每个操作(即添加,获取等),我打开一个EntityManager,启动事务执行操作,提交然后关闭EntityManager 和EntityManagerFactory 。
每次创建服务实例时,您都应该不打开和关闭EntityManagerFactory
。创建EntityManagerFactory
是一项非常昂贵的操作,应该只在应用程序的生命周期内完成一次。为了说明这一点,这里有一个非常基本的启动示例,展示了如何使用实用程序类来处理它:
public class JpaUtil {
private JpaUtil() {}
private static EntityManagerFactory emf = null;
static {
try {
emf = Persistence.createEntityManagerFactory("MyPu");
} catch (Throwable ex) {
throw new ExceptionInInitializerError(ex);
}
}
public static EntityManager getEntityManager() {
return emf.createEntityManager();
}
}
但是虽然你可以使它更复杂(使用一些ThreadLocal
,但请参阅this example),这不会删除EntityManager生命周期和事务管理代码。
我希望在Java EE环境之外拥有一个manged持久化上下文。
然后你需要某种容器来为你做这件事,Spring将是一个明显的候选者,可以用于声明式事务管理和Spring bean中EntityManager
的注入,即使在Java中也是如此SE环境。
博文Using JPA in Spring without referencing Spring使用以下内容精确地说明了如何执行此操作:
LocalEntityManagerFactoryBean
创建EntityManagerFactory
JpaTransactionManager
来管理JPA交易<tx:annotation-driven />
告诉Spring寻找@Transactional
- 你的bean定义!
并提供一个示例Spring配置文件,可帮助您入门。
答案 2 :(得分:1)
实际上,在Java EE环境之外使用JPA有很多支持。参见:
这两种方法都在Java EE环境内外工作。
正如您所提到的,在常规Java EE环境之外,您会遇到“打开EntityManager
,启动事务,提交事务,并关闭EntityManager
循环,这是一个PITA进行编程和维护。
为了获得EE环境的好处,我建议使用Spring框架的JPA部分。文档是aplenty,有很多示例。具体来说,JpaDaoSupport
类和Transactional
注释提供了大量支持。
这使您可以在没有EE环境的情况下执行此类操作:
import java.util.List;
import org.springframework.orm.jpa.support.JpaDaoSupport;
public class SpeakerDAOImpl extends JpaDaoSupport implements SpeakerDAO {
public Speaker findSpeaker(long id) {
return getJpaTemplate().find(Speaker.class,id);
}
@Transactional
public void saveSpeaker(Speaker s) {
getJpaTemplate().persist(s);
}
}
一些教程,文档等:
答案 3 :(得分:0)
这不能回答你的问题,但Ebean ORM使用JPA映射(@Entity等),但“自动管理持久化上下文” - 这意味着你不需要管理EntityManager。
Ebean不支持JPA API(它有一个'无会话'API - 没有EntityManager,没有附加/分离的bean等)但是如果你正在寻找一个简单的路由而没有管理EntityManager的麻烦那么它可能是值得的一看。