我正在使用Struts 1.3 + JPA(使用Hibernate作为持久性提供程序)开发一个简单的“ Book
Store”项目。我不能切换到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操作。理想情况下,所有与数据访问相关的调用都应委派给持久层。例如,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
不是线程安全的,我引入了一个名为helper的类,该类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;
}
}
一切似乎正常,但是我仍然有一些担忧。即:
谢谢
在过去的几天中,我设计了一个可能的解决方案。我试图用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();
}
}
这样的类确保每个线程(即每个请求)将获得其自己的EntityManager
实例。因此,每个DAO对象可以EntityManager
通过调用获得正确的实例EntityManagerHelper.getEntityManager()
根据每次请求会话模式,每个请求必须打开和关闭其自己的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模式中的Open
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>
我的数据库中有两个3表: 在我的UserAccount实体中,我有以下行: 这是为了显示所有表之间的关系。但是,当我部署时,我得到以下错误: 我不确定如何准确解释此错误消息。我假设在实体中没有正确建模表关系。但我不知道为什么。在今天之前,这是很好的编译。有人能提供帮助吗?
下面的代码来自specs。我不明白为什么中需要。 有人能提供一个恰当的解释吗?
问题内容: 我需要像下面这样转换一个Hibernate条件查询 但是在JPA(2)中,我不知道如何实现投影-在这种情况下-是总和。奇怪的是,Hibernate和JPA(甚至是Hibernate JPA 2)具有如此巨大的差异,尤其是在条件查询中。 我开始 但是不知道如何在这里实现投影,也没有别名 问题答案: 这是一个老问题,但让我们举个例子: 使用Hibernate,与Hibernate不同,您总
问题内容: 给定以下结构,我想执行以下SQL的HQL或CriteriaQuery等效项: 我想找回与给定人员关联的位置列表,其creationDate在给定位置之后。 提前致谢! 标记 编辑***:我已经编辑了SQL,因为这有点误导。我不想独立查询位置。 问题答案: 这是不可能的,您无法查询。从JPA Wikibook: 嵌入式收藏 的映射可以被用来定义的集合 的对象。这不是对象的典型用法,因为对