Hibernate exception in open sessions. How can I debug this?

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 here getSession().getTransaction().commit(); } 

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);//--> Exception thrown here 
+4
source share
1 answer

The error means that you are trying to bind an object loaded in one session using another session. There is a big problem with the way you perform session management, but I cannot comment on this without additional information. The merge you are trying to solve can fix the problem with a simple change - use the link returned by the merge method for further work.

 @Override public void makeTransient(T entity) { T newEntityRef = getSession().merge(entity); getSession().getTransaction().begin(); getSession().delete(newEntityRef); getSession().getTransaction().commit(); } 

The problem is with this piece of code.

 Order order = getFactory().getOrderDAO().findById(Long.valueOf(orderId), false); getFactory().getOrderDAO().makeTransient(order);//--> Exception thrown here 

Assuming getOrderDao () creates a new instance of the OrderDao class. The findById call uses a new instance of the session (let's call it s1) to load the object. The loaded object is a proxy server that is associated with the session that was used to download it. Then the next call creates a new OrderDAO (by calling the getOrderDAO method) - now when makeTransient is called by a new session (let's call it s2), it is created. Now you are trying to pass the proxy downloaded from s1 to s2 - this is what this exception indicates. The Merge method accepts an object and either creates a new object in s2, or merges the content with an existing object — in any way that the transmitted input object does not change — the new object that is created will be the return value.

Writing code in this way will also fix the problem without merging.

 OrderDao orderDao = getFactory().getOrderDAO(); Order order = orderDao.findById(Long.valueOf(orderId), false); orderDao.makeTransient(order); 

Another problem with the code above is that the session does not close. Each session uses a JDBC connection, so this will result in a connection leak.

Take a look at the following to understand how to fix your code. Basically, your DAO should not open a new session and should not manage transactions. You have to do it outside.

http://community.jboss.org/wiki/SessionsAndTransactions

http://community.jboss.org/wiki/GenericDataAccessObjects

+6
source

Source: https://habr.com/ru/post/1383343/


All Articles