我有一个jsf项目,当你点击一个链接进入页面时,会调用一个运行查询来填充所述页面上显示的列表的方法。
但是,当我在两个打开的标签页或两个不同的浏览器同时打开链接时,其中一个似乎正在关闭会话而另一个仍在工作,我得到了例外
Servlet.service() for servlet [Faces Servlet] in context with path [/wplexeo] threw exception [Session is closed!] with root cause
这是代码。调用的方法是每次调用时打开和关闭会话的execuNamedQuery。我虽然ThreadLocal应该避免这种情况,或者我现在不应该关闭会议。
private static ThreadLocal<Session> sessions = new ThreadLocal<Session>();
private static ThreadLocal<Transaction> transactions = new ThreadLocal<Transaction>();
private static SessionFactory sessionFactory;
static
{
HibernateUtil.sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}
public List<? extends Entity> executesNamedQuery(final String query, final Map<String, Object> parameters)
throws DaoHibernateException
{
this.openSessionAndBeginTransaction();
final Query namedQuery = this.session.getNamedQuery(query);
if (parameters != null)
{
for (final String paramName : parameters.keySet())
{
namedQuery.setParameter(paramName, parameters.get(paramName));
}
}
final List<? extends Entity> result = namedQuery.list();
this.commitTransactionAndCloseSession();
return result;
}
private void openSessionAndBeginTransaction() throws DaoHibernateException
{
this.session = HibernateUtil.openSession();
try
{
this.transaction = HibernateUtil.beginTransaction();
}
catch (final HibernateException e)
{
System.out.println(e.getCause());
throw new DaoHibernateException(ExceptionType.ABRIR_TRANSACAO, e, null);
}
}
public static Session openSession()
{
HibernateUtil.sessions.set(HibernateUtil.sessionFactory.openSession());
return HibernateUtil.sessions.get();
}
public static Transaction beginTransaction()
{
HibernateUtil.transactions.set(currentSession().beginTransaction());
return HibernateUtil.transactions.get();
}
private void commitTransactionAndCloseSession() throws DaoHibernateException
{
try
{
this.transaction.commit();
}
catch (final HibernateException e)
{
throw new DaoHibernateException(ExceptionType.COMITTAR_TRANSACAO, e, null);
}
finally
{
HibernateUtil.closeCurrentSession();
}
}
/**
* Fecha a Session corrente
*/
public static void closeCurrentSession()
{
HibernateUtil.sessions.get().close();
HibernateUtil.sessions.set(null);
}
我是否在错误的时间关闭了会话?我该什么时候关闭它?我是以错误的方式使用ThreadLocal吗?我现在没有改变数据,只是检索,所以我应该可以让两个用户同时进入同一页面吗?
答案 0 :(得分:2)
我没有运行并测试过这段代码。根据我对Hibernate及其会话和事务工作方式的理解,我认为下面的代码应该可以帮助您实现目标。 Reference credit
import java.util.List;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.metamodel.domain.Entity;
public final class HibernateTLDao {
private static final ThreadLocal<Session> threadSession = new ThreadLocal<Session>();
private static final ThreadLocal<Transaction> threadTransaction = new ThreadLocal<Transaction>();
private static SessionFactory sessionFactory;
static {
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}
public List<? extends Entity> executesNamedQuery(final String query, final Map<String, Object> parameters) {
beginTransaction();
final Query namedQuery = threadSession.get().getNamedQuery(query);
if (parameters != null) {
for (final String paramName : parameters.keySet()) {
namedQuery.setParameter(paramName, parameters.get(paramName));
}
}
@SuppressWarnings("unchecked")
final List<? extends Entity> result = namedQuery.list();
commitTransaction();
return result;
}
public static Session getCurrentSession() {
Session s = threadSession.get();
try {
if (s == null || !s.isOpen()) {
s = sessionFactory.openSession();
threadSession.set(s);
}
} catch (HibernateException ex) {
ex.printStackTrace();
}
return s;
}
public static void closeSession() {
try {
final Session s = threadSession.get();
if (s != null && s.isOpen()) {
s.close();
}
} catch (HibernateException ex) {
ex.printStackTrace();
} finally {
threadSession.set(null);
}
}
public static void beginTransaction() {
Transaction tx = threadTransaction.get();
try {
if (tx != null && !tx.isActive()) {
tx = null;
threadTransaction.set(null);
}
if (tx == null) {
if (threadSession.get() != null && threadSession.get().isOpen()) {
threadSession.get().close();
threadSession.set(null);
}
tx = getCurrentSession().beginTransaction();
threadTransaction.set(tx);
}
} catch (HibernateException ex) {
ex.printStackTrace();
} finally {
if (threadSession.get() == null || !threadSession.get().isOpen()) {
getCurrentSession();
} else {
threadSession.get().clear();
}
}
}
public static void commitTransaction() {
final Transaction tx = threadTransaction.get();
try {
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
Session s = getCurrentSession();
s.flush();
tx.commit();
}
} catch (HibernateException ex) {
rollbackTransaction();
ex.printStackTrace();
} finally {
threadTransaction.set(null);
closeSession();
}
}
public static void rollbackTransaction() {
final Transaction tx = threadTransaction.get();
try {
if (tx != null && !tx.wasCommitted() && !tx.wasRolledBack()) {
tx.rollback();
}
} catch (HibernateException ex) {
ex.printStackTrace();
} finally {
threadTransaction.set(null);
closeSession();
}
}
}