Hi Guys,
Hope you can help me out with this. I've recently switched to Hibernate and this problem keeps cropping up. Here's the problem code: (slightly paraphrased
Code:
QuestionManager qm = new QuestionManager();
LearningNodeManager lnm = new LearningNodeManager();
LearningNode ln = null;
Question q1 = null;
ln = lnm.getNode(1); //gets node 1 from db
q1 = new Question("title1", "question1", ln);
qm.insertQuestionIntoDB(q1);
I think because it accesses the DB with 1 session to get the Learning Node, and another for the question, I get the following exception:
Code:
org.hibernate.SessionException: Session was already closed
at org.hibernate.impl.SessionImpl.close(SessionImpl.java:275)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:301)
at $Proxy0.close(Unknown Source)
at com.samatkinson.structures.QuestionManager.insertQuestionIntoDB(QuestionManager.java:144)
at com.samatkinson.servlets.Tutor.NodeManagerServlet.saveQuestion(NodeManagerServlet.java:98)
at com.samatkinson.servlets.Tutor.NodeManagerServlet.doPost(NodeManagerServlet.java:65)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:710)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:803)...
I'll put the hibernate and class files below. My Basic question is, a) how do I fix this, and b) What is the permanent solution for using managers like this to control DB access, as it keeps cropping up. Normally setting lazy="false" works, but it hasn't this time.
Cheers!!
LearningNode.hbm.xml:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.samatkinson.structures.graph.LearningNode"
table="learning_nodes" lazy="false">
<id name="id" column="node_id" type="java.lang.Integer">
<generator class="increment" />
</id>
<property name="name" />
<property name="info" />
<!-- put stuff in here for owner -->
<many-to-one name="owner"
class="com.samatkinson.structures.User" column="owner_id" />
<bag name="children" table="children" lazy="false">
<key column="parent_id" />
<many-to-many column="child_id"
class="com.samatkinson.structures.graph.LearningNode" />
</bag>
<bag name="parents" table="children" lazy="false" inverse="true">
<key column="child_id" />
<many-to-many column="parent_id"
class="com.samatkinson.structures.graph.LearningNode" />
</bag>
<bag name="registered" table="registered" lazy="false">
<key column="node_id" />
<many-to-many column="user_id"
class="com.samatkinson.structures.User" />
</bag>
<bag name="questions" table="questions" lazy="false" inverse="true">
<key column="question_id" />
<one-to-many
class="com.samatkinson.structures.Question"/>
</bag>
</class>
</hibernate-mapping>
Question.hbm.xml
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.samatkinson.structures.Question"
table="questions" lazy="false">
<id name="id" column="question_id" type="java.lang.Integer">
<generator class="increment" />
</id>
<property name="title"/>
<property name="question" />
<!-- put stuff in here for owner -->
<many-to-one name="node"
class="com.samatkinson.structures.graph.LearningNode" column="node_id" lazy="false" />
</class>
</hibernate-mapping>
Relevant part of LearningNodeManager:
Code:
public LearningNode getNode(int nodeNumber)
throws LearningNodeNotFoundException {
LearningNode ln = null;
Session session = null;
Transaction tx1 = null;
try {
session = HibUtil.getSession();
tx1 = session.beginTransaction();
Query query = session
.createQuery("from LearningNode ln where ln.id = :nodeNumber");
query.setParameter("nodeNumber", nodeNumber);
for (Iterator<LearningNode> it = query.iterate(); it.hasNext();) {
ln = it.next();
}
tx1.commit();
} catch (HibernateException he) {
he.printStackTrace();
if(tx1!=null)tx1.rollback();
}
if (ln != null) {
return ln;
} else {
// will only reach here if no user found
throw new LearningNodeNotFoundException(
"Learning node with number " + nodeNumber + "not found.");
}
}
Relevant part of Question Manager:
Code:
public boolean insertQuestionIntoDB(Question question) {
try {
Session session = HibUtil.getSession();
Transaction tx = session.beginTransaction();
session.save(question);
tx.commit();
session.close();
return true;
} catch (ConstraintViolationException cve) {
cve.printStackTrace();
System.out.println(cve.getConstraintName());
cve.getSQLException();
return false;
} catch (HibernateException he) {
he.printStackTrace();
return false;
}
}
HibUtil:
Code:
package com.samatkinson.utils;
import org.hibernate.*;
import org.hibernate.cfg.*;
// TODO: Auto-generated Javadoc
/**
* The Class HibUtil.
*/
public class HibUtil {
/** The Constant sessionFactory. */
private static final SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (Throwable ex) {
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
* Gets the session factory. The session Factory should only exist once
* per session, as a result this hibutil returns the factory, or instantiates it
* if it's the first call.
*
* @return the session factory
*/
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession(){
return HibUtil.getSessionFactory().getCurrentSession();}
}
If you need anything else just let me know. Cheers!! Any help you can offer will be greatly appreciated.