Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/hibernate/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hibernate JSE中带有JPA的EntityManager线程本地模式_Hibernate_Thread Safety_Struts_Entity_Jpa 2.0 - Fatal编程技术网

Hibernate JSE中带有JPA的EntityManager线程本地模式

Hibernate JSE中带有JPA的EntityManager线程本地模式,hibernate,thread-safety,struts,entity,jpa-2.0,Hibernate,Thread Safety,Struts,Entity,Jpa 2.0,我正在使用Struts 1.3+JPA(以Hibernate作为持久性提供者)开发一个简单的“书店”项目。我不能切换到Spring或任何其他更复杂的开发环境(例如Jboss),也不能使用任何特定于Hibernate的技术(例如,Sessionclass) 鉴于我处于JSE环境中,我需要显式地管理整个EntityManager的生命周期 Book实体定义如下: @Entity public class Book { @Id private String isbn; private String

我正在使用Struts 1.3+JPA(以Hibernate作为持久性提供者)开发一个简单的“书店”项目。我不能切换到Spring或任何其他更复杂的开发环境(例如Jboss),也不能使用任何特定于Hibernate的技术(例如,
Session
class)

鉴于我处于JSE环境中,我需要显式地管理整个EntityManager的生命周期

Book
实体定义如下:

@Entity
public class Book {

@Id private String isbn;
private String title;
private Date publishDate;

    // Getters and Setters
}
public class ListBookAction extends Action {

    private BookDAO dao = new BookDAO();

    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        // Retrieve all the books
        List<Book> books = dao.findAll();

        // Save the result set
        request.setAttribute("books", books);

        // Forward to the view
        return mapping.findForward("booklist");
    }

}
我定义了三个
Action
类,分别负责检索所有图书实例、通过ISBN检索单个图书实例以及将分离的图书合并到数据库中

为了增加业务逻辑代码和数据访问代码之间的关注点分离,我引入了一个简单的
BookDAO
对象,它负责执行CRUD操作。理想情况下,所有与数据访问相关的调用都应该委托给持久层。例如,
ListBookAction
的定义如下:

@Entity
public class Book {

@Id private String isbn;
private String title;
private Date publishDate;

    // Getters and Setters
}
public class ListBookAction extends Action {

    private BookDAO dao = new BookDAO();

    @Override
    public ActionForward execute(ActionMapping mapping, ActionForm form,
            HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        // Retrieve all the books
        List<Book> books = dao.findAll();

        // Save the result set
        request.setAttribute("books", books);

        // Forward to the view
        return mapping.findForward("booklist");
    }

}
一切似乎都正常,但我还是有些担心。即:

  • 这是最好的解决方案吗?在这种情况下,哪种做法是最好的
  • 我仍然需要明确地关闭EntityManager和EntityManager工厂。我该怎么做

  • 谢谢

    在过去的几天里,我设计了一个可能的解决方案。我试图用
    BookUnitSession
    类构造的实际上是
    EntityManagerHelper
    类:

    public class EntityManagerHelper {
    
        private static final EntityManagerFactory emf; 
        private static final ThreadLocal<EntityManager> threadLocal;
    
        static {
            emf = Persistence.createEntityManagerFactory("BookStoreUnit");      
            threadLocal = new ThreadLocal<EntityManager>();
        }
    
        public static EntityManager getEntityManager() {
            EntityManager em = threadLocal.get();
    
            if (em == null) {
                em = emf.createEntityManager();
                threadLocal.set(em);
            }
            return em;
        }
    
        public static void closeEntityManager() {
            EntityManager em = threadLocal.get();
            if (em != null) {
                em.close();
                threadLocal.set(null);
            }
        }
    
        public static void closeEntityManagerFactory() {
            emf.close();
        }
    
        public static void beginTransaction() {
            getEntityManager().getTransaction().begin();
        }
    
        public static void rollback() {
            getEntityManager().getTransaction().rollback();
        }
    
        public static void commit() {
            getEntityManager().getTransaction().commit();
        } 
    }
    
    这种方法还允许视图(例如JSP页面)获取实体的字段,即使这些字段已被惰性初始化(在视图模式中打开会话)。 在JSE环境中,当servlet容器关闭时,需要显式关闭
    EntityManagerFactory
    。这可以通过使用
    ServletContextListener
    对象来完成:

    public class EntityManagerFactoryListener implements ServletContextListener {
    
        @Override
        public void contextDestroyed(ServletContextEvent e) {
            EntityManagerHelper.closeEntityManagerFactory();
        }
    
        @Override
        public void contextInitialized(ServletContextEvent e) {}
    
    }
    
    web.xml
    部署描述符:

    <listener>
      <description>EntityManagerFactory Listener</description>
      <listener-class>package.EntityManagerFactoryListener</listener-class>
    </listener>
    
    <filter>
      <filter-name>interceptor</filter-name>
      <filter-class>package.EntityManagerInterceptor</filter-class>
    </filter>
    
    <filter-mapping>
      <filter-name>interceptor</filter-name>
      <url-pattern>*.do</url-pattern>
    </filter-mapping>
    
    
    EntityManagerFactory侦听器
    package.EntityManagerFactoryListener
    拦截器
    package.EntityManager接收器
    拦截器
    *.做
    
    我在Github中创建的助手工具使用了类似的技术。我选择ServletRequestListener进行生命周期管理,而不是请求过滤器。此外,我没有使用threadlocal,因为如果没有仔细编程,它们在J2EE容器中有内存泄漏的习惯。Tomcat确实有一些技巧可以防止某些人为错误。

    谢谢。我目前使用的Tomcat7和Struts1.3没有任何应用服务器。因此,我要说的是,我并不是完全遵从JEE的。从持久性的角度来看,这就像置身于JSE环境中一样。这就是我在标题中提到JSE的原因。嗨,这个解决方案最终成功了吗?我听说了ThreadLocal用法的一些问题。嗨,这最终解决了,即使我必须对
    EntityManagerAcceptor
    类应用一些小的更改。你指的是什么问题?burton0:我在ThreadLocal上有memleaks(Tomcat给了我警告);我的解决方案是添加一个@WebListener来实现ServletRequestListener接口;并在requestdestromed()方法中执行清理,即threadLocal.remove()。还有,帮个忙。我目前在一个Spring项目中,我迫切需要摆脱Spring。您介意分享您的EntityManager接收器的最终版本吗?也许是谷歌代码,或者别的什么?我真的很感激。对于非Spring和非EJB用户,这是一个非常需要的示例。谢谢我实现了您的方法,但意识到doFiler()中的代码在每个请求中执行了多次。这是有意的吗?