gpt4 book ai didi

hibernate - JSE 中带有 JPA 的 EntityManager ThreadLocal 模式

转载 作者:行者123 更新时间:2023-12-04 00:22:06 24 4
gpt4 key购买 nike

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

鉴于我在 JSE 环境中,我需要明确管理整个 EntityManager 的生命周期。
Book实体定义如下:

@Entity
public class Book {

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

// Getters and Setters
}

我定义了三个 Action类,它们分别负责检索所有书籍实例、按其 ISBN 检索单个书籍实例以及将分离的书籍合并到数据库中。

为了增加业务逻辑代码和数据访问代码之间的关注点分离,我介绍了一个简单的 BookDAO对象,负责执行 CRUD 操作。理想情况下,所有与数据访问相关的调用都应该委托(delegate)给持久层。例如, ListBookAction定义如下:
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");
}

}

BookDAO 对象需要访问 EntityManager实例以执行任何操作。鉴于 EntityManger不是线程安全的,我引入了一个名为 BookUnitSession 的辅助类它将 EntityManager 封装在 ThreadLocal 中多变的:
public class BookUnitSession {

private static EntityManagerFactory emf = Persistence.createEntityManagerFactory("BookStoreUnit");
private static final ThreadLocal<EntityManager> tl = new ThreadLocal<EntityManager>();

public static EntityManager getEntityManager() {
EntityManager em = tl.get();

if (em == null) {
em = emf.createEntityManager();
tl.set(em);
}
return em;
}

}

一切似乎都有效,但我仍然有些担心。即:
  • 这个解决方案是最好的吗?在这种情况下,最佳做法是什么?
  • 我仍然需要明确关闭 EntityManager 和 EntityManagerFactory。我怎样才能做到这一点?

  • 谢谢

    最佳答案

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

    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();
    }
    }

    这样的类确保每个线程(即每个请求)都将获得自己的 EntityManager实例。因此,每个 DAO 对象都可以获得正确的 EntityManager通过调用 EntityManagerHelper.getEntityManager() 进行实例化

    根据每个请求的 session 模式,每个请求都必须打开和关闭自己的 EntityManager例如,它将负责将所需的工作单元封装在事务中。这可以通过实现为 ServletFilter 的拦截过滤器来完成。 :
    public class EntityManagerInterceptor implements Filter {

    @Override
    public void destroy() {}

    @Override
    public void init(FilterConfig fc) throws ServletException {}

    @Override
    public void doFilter(ServletRequest req, ServletResponse res,
    FilterChain chain) throws IOException, ServletException {

    try {
    EntityManagerHelper.beginTransaction();
    chain.doFilter(req, res);
    EntityManagerHelper.commit();
    } catch (RuntimeException e) {

    if ( EntityManagerHelper.getEntityManager() != null && EntityManagerHelper.getEntityManager().isOpen())
    EntityManagerHelper.rollback();
    throw e;

    } finally {
    EntityManagerHelper.closeEntityManager();
    }
    }
    }

    这种方法还允许 View (例如,JSP 页面)获取实体的字段,即使它们已经被延迟初始化(在 View 中打开 session 模式)。
    在 JSE 环境中 EntityManagerFactory servlet 容器关闭时需要显式关闭。这可以通过使用 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>

    关于hibernate - JSE 中带有 JPA 的 EntityManager ThreadLocal 模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15071238/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com