Singleton DAO 实例在 HTTP 事务之间保持旧的关闭会话
Singleton DAO instance keeps old closed session between HTTP transactions
我正在尝试使用 Hibernate 实现 "One-session-per-http-request" 模式,它适用于第一个请求:servlet 的 doGet() 方法打开会话,获取一些内容,然后关闭会话。
但是当我刷新浏览器时,我的 DAO Singleton 实例(其构造函数从 SessionFactory 获取会话)被第二次调用,但仍然使用旧的会话对象(不再调用单例构造函数)。然后我得到一个 "Session is closed" 错误。
我想单例实例必须保存在 HTTP 请求之间的缓存中,所以:我怎样才能再次调用 DAO 单例构造函数? (或者另一个拥有新的 SessionFactory 会话对象的优雅解决方案?)
非常感谢
小服务程序:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Gets the session, eventually creates one
Session s = HibernateUtil.currentSession();
// Gets data from singleton DAO instance
MySingletonDAO o = MySingletonDAO.getInstance();
List<Stuff> stuff = o.getAllTheStuff();
// send it to the view
request.setAttribute("foo",stuff);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue);
dispatcher.forward(request, response);
}
/* error handling blah blah */
finally {
// closing the session
HibernateUtil.closeSession();
}
MySingletonDAO.java :
public class MySingletonDAO {
// Usual singleton syntax
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private Session session;
private MySingletonDAO() {
session = HibernateUtil.currentSession();
System.out.println("This constructor is called only on the first HTTP transaction");
}
public List<Stuff> getAllTheStuff() {
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
经典线程安全HibernateUtil.java :
public class HibernateUtil {
private static final SessionFactory sessionFactory;
public static final ThreadLocal session = new ThreadLocal();
static {
try {
// Creates the SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he) {
throw new RuntimeException("Conf problem : "+ he.getMessage(), he);
}
}
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// Opens a new Session, if this Thread has none
if (s == null || !s.isOpen() ) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
你的要求没有意义:如果在每次请求时都调用单例的构造函数,它就不再是单例了。会话确实在请求结束时关闭,但 DAO 保留对会话的引用,而不是每次调用时从您的 util class 获取它。
你的 DAO 代码应该是
public class MySingletonDAO {
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private MySingletonDAO() {
}
public List<Stuff> getAllTheStuff() {
Session session = HibernateUtil.currentSession();
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
也就是说,事务应该以声明方式处理,并且应该在服务层而不是 DAO 层处理:事务通常使用多个 DAO,DAO 返回的实体应该保持托管状态,所有访问和访问对这些实体所做的修改应在事务内进行。
我强烈建议使用 Java EE 容器或 Spring 来为您处理事务和会话处理。您还应该使用标准的 JPA API 而不是专有的 Hibernate API.
我正在尝试使用 Hibernate 实现 "One-session-per-http-request" 模式,它适用于第一个请求:servlet 的 doGet() 方法打开会话,获取一些内容,然后关闭会话。
但是当我刷新浏览器时,我的 DAO Singleton 实例(其构造函数从 SessionFactory 获取会话)被第二次调用,但仍然使用旧的会话对象(不再调用单例构造函数)。然后我得到一个 "Session is closed" 错误。
我想单例实例必须保存在 HTTP 请求之间的缓存中,所以:我怎样才能再次调用 DAO 单例构造函数? (或者另一个拥有新的 SessionFactory 会话对象的优雅解决方案?)
非常感谢
小服务程序:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
// Gets the session, eventually creates one
Session s = HibernateUtil.currentSession();
// Gets data from singleton DAO instance
MySingletonDAO o = MySingletonDAO.getInstance();
List<Stuff> stuff = o.getAllTheStuff();
// send it to the view
request.setAttribute("foo",stuff);
RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue);
dispatcher.forward(request, response);
}
/* error handling blah blah */
finally {
// closing the session
HibernateUtil.closeSession();
}
MySingletonDAO.java :
public class MySingletonDAO {
// Usual singleton syntax
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private Session session;
private MySingletonDAO() {
session = HibernateUtil.currentSession();
System.out.println("This constructor is called only on the first HTTP transaction");
}
public List<Stuff> getAllTheStuff() {
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
经典线程安全HibernateUtil.java :
public class HibernateUtil {
private static final SessionFactory sessionFactory;
public static final ThreadLocal session = new ThreadLocal();
static {
try {
// Creates the SessionFactory
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he) {
throw new RuntimeException("Conf problem : "+ he.getMessage(), he);
}
}
public static Session currentSession() throws HibernateException {
Session s = (Session) session.get();
// Opens a new Session, if this Thread has none
if (s == null || !s.isOpen() ) {
s = sessionFactory.openSession();
session.set(s);
}
return s;
}
public static void closeSession() throws HibernateException {
Session s = (Session) session.get();
session.set(null);
if (s != null)
s.close();
}
}
你的要求没有意义:如果在每次请求时都调用单例的构造函数,它就不再是单例了。会话确实在请求结束时关闭,但 DAO 保留对会话的引用,而不是每次调用时从您的 util class 获取它。
你的 DAO 代码应该是
public class MySingletonDAO {
private static MySingletonDAO INSTANCE = new MySingletonDAO();
public static MySingletonDAO getInstance() { return INSTANCE;}
private MySingletonDAO() {
}
public List<Stuff> getAllTheStuff() {
Session session = HibernateUtil.currentSession();
try {
session.beginTransaction();
Query q = session.createQuery("FROM StuffDBTable");
session.getTransaction().commit();
return (List<Stuff>) q.list();
}
}
}
也就是说,事务应该以声明方式处理,并且应该在服务层而不是 DAO 层处理:事务通常使用多个 DAO,DAO 返回的实体应该保持托管状态,所有访问和访问对这些实体所做的修改应在事务内进行。
我强烈建议使用 Java EE 容器或 Spring 来为您处理事务和会话处理。您还应该使用标准的 JPA API 而不是专有的 Hibernate API.