-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Transaction, Association, dirty collections
PostPosted: Mon Dec 18, 2006 11:32 am 
Newbie

Joined: Wed Feb 22, 2006 9:30 am
Posts: 13
Location: Cologne, Germany
Hibernate version: 3.2
Name and version of the database you are using: MySQL 4

Hi everybody,

I'm having a strange problem regarding transactions and re-associated objects. During a checkout process I'm collecting the pieces of information needed for a complete order. This is done using several distinct requests.

Maybe I'm just thinking in the wrong direction, so any feedback is appreciated:

A little comment for the attached class: In the first block I'm creating a new Order object and saving it in the database. Within the second block I'm adding a status information but then something unexpeced happens and I'd like to undo the settings done so far.

Until now everything is fine, but when I start adding another status information an Exception occurs:

Code:
Exception in thread "main" org.hibernate.HibernateException: reassociated object has dirty collection
   at org.hibernate.event.def.OnLockVisitor.processCollection(OnLockVisitor.java:45)
   at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:101)
   at org.hibernate.event.def.AbstractVisitor.processValue(AbstractVisitor.java:61)
   at org.hibernate.event.def.AbstractVisitor.processEntityPropertyValues(AbstractVisitor.java:55)
   at org.hibernate.event.def.AbstractVisitor.process(AbstractVisitor.java:123)
   at org.hibernate.event.def.AbstractReassociateEventListener.reassociate(AbstractReassociateEventListener.java:78)
   at org.hibernate.event.def.DefaultLockEventListener.onLock(DefaultLockEventListener.java:59)
   at org.hibernate.impl.SessionImpl.fireLock(SessionImpl.java:584)
   at org.hibernate.impl.SessionImpl.lock(SessionImpl.java:576)
   at test.hibernate.Test.main(Test.java:64)


So from the error message it seems that the rollback operation doesn't reset the status information as expeced. Any idea what I am doing wrong?

My test class:

Code:
package test.hibernate;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;

import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
import org.hibernate.cfg.AnnotationConfiguration;

public class Test {

  public static void main(String[] args) throws Exception {

    AnnotationConfiguration annotationConfig = new AnnotationConfiguration();
    annotationConfig.addAnnotatedClass(Order.class);
    annotationConfig.addAnnotatedClass(OrderStatus.class);
    annotationConfig.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLMyISAMDialect");
//    Also tried InnoDB - same result
//    annotationConfig.setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect");
    annotationConfig.setProperty("hibernate.connection.driver_class", "com.mysql.jdbc.Driver");
    annotationConfig.setProperty("hibernate.connection.url", "jdbc:mysql://foo/bar");
    annotationConfig.setProperty("hibernate.connection.username", "yyyy");
    annotationConfig.setProperty("hibernate.connection.password", "xxxx");
    annotationConfig.setProperty("hibernate.hbm2ddl.auto", "update");

    SessionFactory sessionFactory = annotationConfig.buildSessionFactory();

    // Block A
    Session orderSession = sessionFactory.openSession();
    Transaction t = orderSession.beginTransaction();
    Order newOrder = new Order();
    orderSession.saveOrUpdate(newOrder);
    t.commit();
    orderSession.close();

    // Block B
    orderSession = sessionFactory.openSession();
    t = orderSession.beginTransaction();
    orderSession.lock(newOrder, LockMode.NONE);
    newOrder.addStatusToHistory(new OrderStatus());
    // ...
    // Something happens now which forces us to undo the changes
    // made so far
    // ...
    t.rollback();
    orderSession.close();

    // Block C
    orderSession = sessionFactory.openSession();
    t = orderSession.beginTransaction();
    orderSession.lock(newOrder, LockMode.NONE);
    newOrder.addStatusToHistory(new OrderStatus());
    t.commit();
    orderSession.close();

  }

  @Entity
  @Table(name="Test_Order")
  public static class Order {

    private int myOrderID = 0;
    private List<OrderStatus> myStatusHistory = new ArrayList<OrderStatus>();

    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    public int getOrderID() {
      return this.myOrderID;
    }
    public void addStatusToHistory(OrderStatus orderStatus) {
      this.getStatusHistory().add(orderStatus);
      orderStatus.setOrder(this);
    }
    public void setOrderID(int orderID) {
      this.myOrderID = orderID;
    }

    @OneToMany @JoinColumn(name="Order_Id")
    @Cascade(value=CascadeType.ALL)
    public List<OrderStatus> getStatusHistory() {
      return this.myStatusHistory;
    }
    public void setStatusHistory(List<OrderStatus> statusHistory) {
      this.myStatusHistory = statusHistory;
    }

  }

  @Entity
  @Table(name="Test_Order_Status")
  public static class OrderStatus {

    private Order myOrder = null;
    private int myOrderStatusID = 0;

    @Id @GeneratedValue(strategy=GenerationType.AUTO)
    public int getOrderStatusID() {
      return this.myOrderStatusID;
    }
    public void setOrderStatusID(int orderStatusID) {
      this.myOrderStatusID = orderStatusID;
    }

    @ManyToOne @JoinColumn(name="Order_Id")
    public Order getOrder() {
      return this.myOrder;
    }
    public void setOrder(Order order) {
      this.myOrder = order;
    }

  }

}


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 19, 2006 8:10 am 
Expert
Expert

Joined: Tue Dec 28, 2004 7:02 am
Posts: 573
Location: Toulouse, France
After receiving the exception, did you try reusing the session you were using when the tx failed and was rollbacked? If so, just trash the session object. Never reuse a session when an associated tx has failed, (it's not my opinion, it' one the Hibernate best practices).

_________________
Baptiste
PS : please don't forget to give credits below if you found this answer useful :)


Top
 Profile  
 
 Post subject:
PostPosted: Tue Dec 19, 2006 8:13 am 
Newbie

Joined: Wed Feb 22, 2006 9:30 am
Posts: 13
Location: Cologne, Germany
batmat wrote:
After receiving the exception, did you try reusing the session you were using when the tx failed and was rollbacked?

I used a new Session.


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.