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