手动管理持久化上下文的技巧

时间:2010-08-24 13:30:39

标签: java design-patterns orm jpa persistence

我正在调查使用JPA获取我的数据访问代码。我正在尝试编写业务层和数据访问层,以便它可以在Web应用程序和Java SE应用程序中工作。因此我不能使用容器管理的持久化上下文。我使用JPA的大部分内容都在容器管理环境中显示了示例。

每次我在创建服务类的新实例时都会获得EntityManagerFactory。对于每个操作(即添加,获取等),我打开一个EntityManager,启动事务执行操作,提交然后关闭EntityManager和EntityManagerFactory。我希望在Java EE环境之外有一个manged持久化上下文的好处。

不使用容器管理上下文时是否有最佳做法?是否有任何Java EE独立持久化上下文管理器?有推荐的模式吗?

谢谢,

的Al

更新

感谢eveyone提供的信息。一切都非常有用。

4 个答案:

答案 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的麻烦那么它可能是值得的一看。