2011-11-27 53 views
4

我在hybernate新手,我有以下异常艰难:打开会话时发生Hibernate异常。我怎样才能调试呢?

异常在线程“AWT-EventQueue的 - 0” org.hibernate.HibernateException:非法尝试将 代理有两个打开的会话关联

我试着删除一个对象(一个订单)时得到这个。

我的设置/代码:

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> 

会话持有人:

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();   
    }  



} 

以及相关的DAO都延长了以下内容:

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(); 


    } 


} 

虽然所有的其他查询工作(例如,插入/选择其他实体和顺序),当我尝试删除我得到GenericDAO的代码的以下部分以下异常命令:

public void makeTransient(T entity) { 
    getSession().getTransaction().begin(); 
    getSession().delete(entity);//--> Exception here 
    getSession().getTransaction().commit(); 


} 

的异常堆栈跟踪:

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) 

只有在我删除订单时才会发生这种情况(这就是为什么我只发布了部分代码)。

我不明白这个例外的含义。
但谷歌搜索我想它做了以下工作:
1)会议合并:

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


} 

2)关闭会话并重新打开:

public Session getSession() { 
    if(session == null || !session.isOpen()){ 
     session = DBUtil.getSessionFactory().openSession(); 
    } 
      else{ 
       session.close(); 
       session = DBUtil.getSessionFactory().openSession(); 
      } 

    return session; 
} 

我坚持关于如何调试这个。

任何投入是非常值得欢迎的

UPDATE:

额外的信息:
员工映射:

<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> 

客户映射:

<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(); 


    } 


} 

启动异常的代码:

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

你在哪里调用函数删除订单? – Zohaib

+0

+1在这个问题的细节 –

回答

6

的错误意味着您正试图加载在一个会话与另一个会话的对象相关联。如何进行会话管理存在更大的问题 - 但如果没有更多信息,我无法对此发表评论。您尝试的合并工作可以通过简单的更改来解决问题 - 使用合并方法返回的引用进行进一步操作。

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

问题出在这段代码。

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

假设getOrderDao()正在创建OrderDao类的新实例。对findById的调用使用一个新的会话实例(我们称之为s1)来加载对象。加载的对象是与用于加载它的会话相关联的代理。然后下一个调用创建一个新的OrderDAO(通过调用getOrderDAO方法) - 现在,当makeTransient被调用一个新的会话(让我们称这个s2)创建。您现在正在尝试将由s1加载的代理传递给s2 - 这是异常指示的内容。合并方法接受对象,并在s2中创建一个新对象或将内容与现有对象合并 - 无论输入对象传递的方式是否改变 - 创建的新对象都将是返回值。

通过这种方式编写代码也可以解决问题,而无需合并。

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

上述代码的另一个问题是会话没有关闭。每个会话都使用JDBC连接 - 所以会导致连接泄漏。

查看以下内容,了解如何修复代码。基本上你的DAO不应该开一个新的会话,并且不应该管理事务。你应该在外面去做。

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

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

+0

好的,一旦我尝试这个,我会让你知道它是否工作。所以你说我的所有DAO都是错的? – Cratylus

+1

+1这似乎解决了这个问题。你需要更多的信息来帮助我理解我是如何搞乱会话管理的? – Cratylus

+0

这取决于 - 如果您使用多个线程中的相同实例,则DAO实现是错误的。此外,事务通常不是DAO方法,而是更高级别的异常处理,会话应该是短暂的 - 在一组操作之后关闭。你应该看看springframeworks的做法 - 或者使用simlet。 – gkamal

相关问题