据我所知,每个请求的会话意味着每个servlet请求只能使用一个hibernate会话,而不是每个事务一个会话。
考虑这个助手类:
public class HibernateUtil {
private static SessionFactory sessionFactory;
// this is called by the servlet context listener
public static void buildSessionFactory() {
// build session factory
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
// check if the entity user already exist in the database
public static User getUser(String email) {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
User user = (User)session.createQuery("from User c where c.emailAddress like :email").setParameter("email", email).uniqueResult();
session.getTransaction().commit();
return user;
}
// if getUser returns null, insert this user in the database
public static void insertUser(User user) {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
session.save(user);
session.getTransaction().commit();
}
}
现在每个方法都有自己的会话对象,但是当调用寄存器servlet时我必须这样做:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
User user = // initialise user
if (getUser(request.getParameter("email")) == null) { // session
insertUser(user); // another session
request.setAttribute("user", user);
request.getRequestDispatcher("homepage.jsp").forward(request, response);
} else {
request.setAttribute("message", "This account already exist");
populateFields(request);
request.getRequestDispatcher("register.jsp").forward(request, response);
}
}
现在,我的寄存器servlet有效地使用了两个会话,对模式进行了改进。我已经想到了可能的解决方法:
我该怎么办?是否有更好的代码可以做我想做的事情?
答案 0 :(得分:0)
在这种情况下,最好的选择是设计如下:
Session session
作为字段,并允许通过构造函数或setter(由您自己)注入。您的所有Daos都将成为此类的子类。Session session
或作为参数接收它。通过这种方式,服务可以将session
注入其方法中使用的必要daos。这也使服务能够启动和提交/回滚事务。如果您使用像Spring这样的框架来提供与Hibernate的集成,您会发现它们具有类似的设计:
HibernateTemplate
。<transactional>
或@Transactional
将创建一个代理类,它包装您的服务以打开会话,执行正确的服务方法,并提交/回滚操作,具体取决于在那里完成了交易管理。答案 1 :(得分:0)
您可以实现创建会话的filter,然后将其存储在请求中,这样您就可以在有权访问请求对象的任何地方重用它:
public class SessionPerRequestFilter implements Filter {
public static final String SESSION_ATTRIBUTE_NAME = "myapp.hibernate.session";
private static SessionFactory sessionFactory;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// Locate the session on the request object
Session session = (Session) request.getAttribute(SESSION_ATTRIBUTE_NAME);
if(session == null) {
// Create a new session
session = HibernateUtil.getSessionFactory().openSession();
request.setAttribute(SESSION_ATTRIBUTE_NAME, session);
}
try {
// Continue the filter chain
chain.doFilter(request, response);
}
finally {
// Close the session
session.close();
}
}
@Override
public void destroy() {
}
}
在您的servlet中,您可以通过
获取会话Session session = (Session) request.getAttribute(SessionPerRequestFilter.SESSION_ATTRIBUTE_NAME);
确保您只关闭您的交易而不关闭您的帮助程序类中的会话。