2011-11-27 24 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