我目前正在创建一个使用hibernate和mysql公开数据的平台RESTful Web服务。在创建服务时,我遇到了几个关于正确使用Hibernate会话的问题。
我创建了SessionFactory的单例,用于检索新会话。
public class JPAServletContextListener implements ServletContextListener {
private static final Logger log = LoggerFactory.getLogger(JPAServletContextListener.class);
/**
* Initialize the JPAManager.
*/
public void contextInitialized(ServletContextEvent sce) {
JPAManager.initializeJPAManager();
log.info("JPAManager initialized.");
}
public void contextDestroyed(ServletContextEvent sce) {
JPAManager.closeJPAManager();
log.info("JPAManager destroyed successfully.");
}
}
private static SessionFactory sessionFactory;
public static void initializeJPAManager() {
Configuration config = new Configuration();
config.configure("hibernate.cfg.xml");
sessionFactory = config.buildSessionFactory();
}
目前,只要需要一个对象,就会打开会话,检索实体,然后关闭会话。
public static <T> T getEntity(Serializable id, Class<?> klass) {
Transaction txn = null;
Session session = getSessionFactory().openSession();
T entity = null;
try {
txn = session.beginTransaction();
entity = (T) session.get(klass, id);
if (entity == null) {
throw new NullPointerException(String.format("row {} could not be found in the database.", id));
}
txn.commit();
} catch (HibernateException e) {
log.debug("Exception encountered while retrieving {} from the database.", id, e);
} finally {
session.close();
}
return entity;
}
我正在使用Bean Validation API在数据库中的任何信息更新之前验证进入服务的数据。 Bean验证将服务的传入值与数据库值进行比较,以确保例如不将不正确的货币添加到现有订单。每个bean验证都是从数据库中获取一个订单实体,所以如果我在POJO上有10个bean验证,我会看到10个单独的会话开放,检索实体,并通过getEntity()
方法关闭会话。由于服务规模可能会有问题。
更简单的方法是在Jersey请求过滤器中打开hibernate会话,在请求期间保持打开状态,然后在响应过滤器中关闭它?可以通过jboss documentation中列出的getCurrentSession()
检索特定于请求的会话。我会对服务中的数据完整性感到担忧,但性能提升可能会保证这种设计,并且它基于hibernate文档对每个请求的会话设计模式似乎是有效的。