I am new to hybernate and I am struggling with the following exception:
Exception in thread "AWT-EventQueue-0" org.hibernate.HibernateException: illegally trying to associate a proxy with two open sessions
I get this when I try to delete an object (order).
My setup / code:
Order.hbm.xml
<hibernate-mapping> <class name="com.database.entities.Order" table="ORDERS"> <id name="orderId" type="java.lang.Long"> <column name="ORDERID" /> <generator class="identity" /> </id> <property name="product" type="java.lang.String"> <column name="SHIP" /> </property> <property name="orderDate" type="java.util.Date"> <column name="ORDERDATE" /> </property> <property name="quantity" type="java.lang.Integer"> <column name="QUANTITY" /> </property> <many-to-one name="customer" class="com.database.entities.Customer" fetch="join"> <column name="CUSTOMERID"/> </many-to-one> <many-to-one name="associate" column="ASSOCIATEID" class="com.database.entities.Employee" fetch="join"> </many-to-one> </class> </hibernate-mapping>
Session Holder:
public class DBSession { private static SessionFactory sessionFactory; static{ Configuration cfg = new Configuration(); sessionFactory = cfg.configure().buildSessionFactory(); } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void shutdown() { getSessionFactory().close(); } }
And the corresponding DAOs all extend the following:
public abstract class GenericDAO<T, ID extends Serializable> implements GenericDAOIF<T, ID> { private Class<T> persistentClass; private Session session; public Session getSession() { if(session == null || !session.isOpen()){ session = DBUtil.getSessionFactory().openSession(); } return session; } public void setSession(Session session) { this.session = session; } @SuppressWarnings("unchecked") @Override public T findById(ID id, boolean lock) { T entity; if(lock) entity = (T) getSession().load(getPersistentClass(), id, LockMode.UPGRADE); else entity = (T) getSession().load(getPersistentClass(), id); return entity; } @Override public T makePersistent(T entity) { getSession().beginTransaction(); getSession().saveOrUpdate(entity); flush(); getSession().getTransaction().commit(); return entity; } @Override public void flush() { getSession().flush(); } @Override public void clear() { getSession().clear(); } @Override public void makeTransient(T entity) { getSession().getTransaction().begin(); getSession().delete(entity); getSession().getTransaction().commit(); } }
While all other queries work (for example, insert / select for other entities and order), when I try to delete an order, I get the following exception in the following part of the GenericDAO code:
public void makeTransient(T entity) { getSession().getTransaction().begin(); getSession().delete(entity);
Exception stack trace:
Exception in thread "AWT-EventQueue-0" org.hibernate.HibernateException: illegally attempted to associate a proxy with two open Sessions at org.hibernate.proxy.AbstractLazyInitializer.setSession(AbstractLazyInitializer.java:126) at org.hibernate.engine.StatefulPersistenceContext.reassociateProxy(StatefulPersistenceContext.java:573) at org.hibernate.engine.StatefulPersistenceContext.unproxyAndReassociate(StatefulPersistenceContext.java:618) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:89) at org.hibernate.event.def.DefaultDeleteEventListener.onDelete(DefaultDeleteEventListener.java:73) at org.hibernate.impl.SessionImpl.fireDelete(SessionImpl.java:956) at org.hibernate.impl.SessionImpl.delete(SessionImpl.java:934) at com.dao.GenericDAO.makeTransient(GenericDAO.java:100) at com.ui.panels.AdminDBPanel$11.actionPerformed(AdminDBPanel.java:414) at javax.swing.AbstractButton.fireActionPerformed(Unknown Source) at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
This only happens when I delete the order (so I placed only that part of the code).
I do not understand what this exception means.
But when searching on Google, I tried the following: not :
1) Merge with the session:
@Override public void makeTransient(T entity) { getSession().merge(entity); getSession().getTransaction().begin(); getSession().delete(entity); getSession().getTransaction().commit(); }
2) Closing the session and reopening it:
public Session getSession() { if(session == null || !session.isOpen()){ session = DBUtil.getSessionFactory().openSession(); } else{ session.close(); session = DBUtil.getSessionFactory().openSession(); } return session; }
I was fixated on how to debug this.
Any input is welcome
UPDATE:
Additional Information:
Employee Mapping:
<hibernate-mapping> <class name="com.database.entities.Employee" table="ASSOCIATE"> <id name="assosiateId" type="java.lang.Long"> <column name="ASSOCIATEID" /> <generator class="identity" /> </id> <property name="firstName" type="java.lang.String" not-null="true"> <column name="FIRSTNAME" /> </property> <property name="lastName" type="java.lang.String" not-null="true"> <column name="LASTNAME" /> </property> <property name="userName" type="java.lang.String" not-null="true"> <column name="USERNAME" /> </property> <property name="password" type="java.lang.String" not-null="true"> <column name="PASSWORD" /> </property> <set name="orders" table="ORDERS" inverse="true" cascade="all" lazy="true"> <key> <column name="ASSOCIATEID" /> </key> <one-to-many class="com.database.entities.Order" /> </set> </class> </hibernate-mapping> <hibernate-mapping> <class name="com.database.entities.Customer" table="CUSTOMER"> <id name="customerId" type="java.lang.Long"> <column name="CUSTOMERID" /> <generator class="identity" /> </id> <property name="customerName" type="java.lang.String"> <column name="CUSTOMERNAME" /> </property> <set name="orders" table="ORDERS" inverse="true" cascade="all" lazy="true"> <key> <column name="CUSTOMERID" /> </key> <one-to-many class="com.database.entities.Order" /> </set> </class> </hibernate-mapping>
Customer Mapping:
<hibernate-mapping> <class name="com.database.entities.Customer" table="CUSTOMER"> <id name="customerId" type="java.lang.Long"> <column name="CUSTOMERID" /> <generator class="identity" /> </id> <property name="customerName" type="java.lang.String"> <column name="CUSTOMERNAME" /> </property> <set name="orders" table="ORDERS" inverse="true" cascade="all" lazy="true"> <key> <column name="CUSTOMERID" /> </key> <one-to-many class="com.database.entities.Order" /> </set> </class> </hibernate-mapping>
OrderDAO:
public class OrderDAO extends GenericDAO<Order, Long> implements OrderDAOIF { @Override public void addOrder(Order order, Customer customer, Associate associate) { Session session = getSession(); Transaction tx = session.beginTransaction(); order.setAssociate(associate); order.setCustomer(customer); session.saveOrUpdate(order); tx.commit(); session.close(); } @Override public void updateOrderStatus(String status, Long orderId) { Order order = findById(orderId, false); order.setOrderState(status); Session session = getSession(); Transaction tx = session.beginTransaction(); session.saveOrUpdate(order); tx.commit(); session.close(); } }
Code that throws an exception:
Order order = getFactory().getOrderDAO().findById(Long.valueOf(orderId), false); getFactory().getOrderDAO().makeTransient(order);