I have tried to use the evict and lock function to use objects in different sessions. and found some strange exceptions.
Here are my two tests, one with collection and another with persistent object as property. The code may make no sense, i have only tried to understand how evict and lock work.
Code:
Configuration config = new Configuration().configure();
SchemaUpdate su = new SchemaUpdate(config);
su.execute(true);
SessionFactory sfactory = config.buildSessionFactory();
// save the objects in session one
Session session = sfactory.openSession();
Transaction tx = session.beginTransaction();
Member m1 = new Member();
Name n1 = new Name("Smith", "John");
m1.setName(n1);
m1.setEmail("John.Smith@hotmail.com");
m1.setPassword("pw");
Publication pub1 = new Publication();
pub1.setTitle("Hibernate with Aspect");
pub1.setData("blabla");
pub1.setDate(new Date());
Publication pub2 = new Publication();
pub2.setTitle("Transaction with hibernate");
pub2.setData("blabla");
pub2.setDate(new Date());
m1.setPublications(new HashSet());
m1.getPublications().add(pub1);
session.save(m1);
tx.commit();
session.close();
// load object in session2
Session session2 = sfactory.openSession();
tx = session2.beginTransaction();
String str = "select member from model.Member as member";
Query q = session2.createQuery(str);
Member m = (Member)q.list().iterator().next();
//System.out.println(m.getPublications().size());
session2.evict(m);
session2.lock(m1, LockMode.UPGRADE);
m1.getPublications().add(pub2);
session2.update(m1);
tx.commit();
session2.close();
When i comment the System.out.println(m.getPublications().size(), it runs well, but with this code the following exception will be caused.
Code:
net.sf.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: 1, of class: model.Publication
at net.sf.hibernate.impl.SessionImpl.checkUniqueness(SessionImpl.java:1600)
at net.sf.hibernate.impl.SessionImpl.reassociate(SessionImpl.java:1606)
at net.sf.hibernate.impl.SessionImpl.lock(SessionImpl.java:1631)
at net.sf.hibernate.engine.Cascades$2.cascade(Cascades.java:79)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:436)
at net.sf.hibernate.engine.Cascades.cascadeCollection(Cascades.java:526)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:452)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:503)
at net.sf.hibernate.impl.SessionImpl.lock(SessionImpl.java:1635)
at mytest.EvictTest.main(EvictTest.java:129)
Exception in thread "main"
but in the debug i can see, the collection will be evicted.
Code:
14:57:03,746 DEBUG SessionImpl:3485 - evicting [model.Member]
14:57:03,746 DEBUG SessionImpl:3512 - evicting collection: [model.Member.publications#1]
Next test works with address property of a member object. it is also a persistent object.
Code:
Configuration config = new Configuration().configure();
SchemaUpdate su = new SchemaUpdate(config);
su.execute(true);
SessionFactory sfactory = config.buildSessionFactory();
// save the objects in session one
Session session = sfactory.openSession();
Transaction tx = session.beginTransaction();
Member m1 = new Member();
Name n1 = new Name("Smith", "John");
m1.setName(n1);
m1.setEmail("John.Smith@hotmail.com");
m1.setPassword("pw");
Address adr1 = new Address("john_home", "1", new Integer(60599),
"Frankfurt", "Germany");
m1.setAddress(adr1);
Publication pub1 = new Publication();
pub1.setTitle("Hibernate with Aspect");
pub1.setData("blabla");
pub1.setDate(new Date());
m1.setPublications(new HashSet());
m1.getPublications().add(pub1);
pub1.setMembers(new HashSet());
pub1.getMembers().add(m1);
session.save(m1);
tx.commit();
session.close();
Session session2 = sfactory.openSession();
tx = session2.beginTransaction();
String str = "select member from model.Member as member";
Query q = session2.createQuery(str);
Collection ps = q.list();
Member m = (Member)ps.iterator().next();
m.getAddress().setCity("Shanghai");
session2.update(m);
tx.commit();
session2.evict(m);
tx = session2.beginTransaction();
session2.lock(m1, LockMode.UPGRADE);
System.out.println(m1.getAddress().getCity());
session2.update(m1);
tx.commit();
session2.close();
the following exception will be caused.
Code:
net.sf.hibernate.HibernateException: cannot lock an unsaved transient instance: [model.Address]
at net.sf.hibernate.impl.SessionImpl.lock(SessionImpl.java:1629)
at net.sf.hibernate.engine.Cascades$2.cascade(Cascades.java:79)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:436)
at net.sf.hibernate.engine.Cascades.cascade(Cascades.java:503)
at net.sf.hibernate.impl.SessionImpl.lock(SessionImpl.java:1635)
at mytest.EvictTest.main(EvictTest.java:77)
Exception in thread "main"
After the test was run, In the database will 2 address datasets inserted. One with city Frankfurt and another with city Shanghai.
Here is my mapping document
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
<class name="model.Address" table="ADDRESS" select-before-update="true">
<id name="id" type="long" unsaved-value="any">
<column name="ADDRESS_ID" not-null="true" />
<generator class="native" />
</id>
<property name="street">
<column name="street" not-null="false" />
</property>
<property name="number">
<column name="number" not-null="false" />
</property>
<property name="zip">
<column name="zip" not-null="false" />
</property>
<property name="city">
<column name="city" not-null="false" />
</property>
<property name="country">
<column name="country" not-null="false" />
</property>
<many-to-one update="false" insert="false" name="person" class="model.Person" column="PERSON_ID" unique="true" cascade="save-update" />
</class>
<class name="model.Cat" table="CAT" select-before-update="true">
<id name="id" type="long" unsaved-value="any">
<column name="CAT_ID" not-null="true" />
<generator class="native" />
</id>
<property name="name">
<column name="name" not-null="false" />
</property>
<property name="sex">
<column name="sex" not-null="false" />
</property>
<property name="weight">
<column name="weight" not-null="false" />
</property>
</class>
<class name="model.Person" table="PERSON">
<id name="id" type="long" unsaved-value="null">
<column name="PERSON_ID" not-null="true" />
<generator class="native" />
</id>
<discriminator column="type" type="string" />
<component class="model.Name" name="name">
<property name="forename">
<column name="forename" not-null="false" />
</property>
<property name="surname">
<column name="surname" not-null="false" />
</property>
</component>
<many-to-one cascade="all" class="model.Cat" column="CAT_ID" name="cat" unique="true" />
<list name="sizes" table="PERSON_SIZES">
<key column="PERSON_ID" />
<index column="I" />
<element column="sizes" type="string" />
</list>
<!--
<list name="phones" table="PERSON_PHONES">
<key column="PERSON_ID" />
<index column="I" />
<composite-element class="model.Phone" name="phones">
<property name="prefix">
<column name="prefix" not-null="false" />
</property>
<property name="number">
<column name="number" not-null="false" />
</property>
</composite-element>
</list>
-->
<many-to-one cascade="all" class="model.Address" column="ADDRESS_ID" name="address" unique="true" />
<subclass name="model.Member" extends="model.Person">
<property name="email">
<column name="email" not-null="false" />
</property>
<property name="password">
<column name="password" not-null="false" />
</property>
<set name="publications" table="Publication_Member" lazy="true" cascade="save-update">
<key>
<column name="Member_ID" not-null="true" />
</key>
<many-to-many class="model.Publication">
<column name="Publication_ID" not-null="true" />
</many-to-many>
</set>
</subclass>
<subclass extends="model.Person" name="model.SeminarParticipant">
<property name="department">
<column name="department" not-null="false" />
</property>
<property name="email">
<column name="email" not-null="false" />
</property>
<many-to-one cascade="save-update" column="SEMINARTOPIC_ID" insert="false" name="seminarTopic" update="false" />
<many-to-one cascade="save-update" column="SEMINAR_ID" insert="false" name="seminar" update="false" />
<property name="matriculationNo">
<column name="matriculationNo" not-null="false" />
</property>
</subclass>
</class>
<class name="model.Seminar" table="SEMINAR">
<id name="id" type="long" unsaved-value="null">
<column name="SEMINAR_ID" not-null="true" />
<generator class="native" />
</id>
<property name="title">
<column name="title" not-null="false" />
</property>
<property name="description">
<column name="description" not-null="false" />
</property>
<many-to-one name="semester" column="SEMESTER_ID" insert="false" update="false" cascade="save-update" />
<many-to-one name="member" class="model.Member" column="MEMBER_ID" unique="true" cascade="save-update" />
<list name="seminarTopics" lazy="true" cascade="all">
<key column="SEMINAR_ID" />
<index column="I" />
<one-to-many class="model.SeminarTopic" />
</list>
<list name="seminarParticipants" lazy="true" cascade="save-update">
<key column="SEMINAR_ID" />
<index column="I" />
<one-to-many class="model.SeminarParticipant" />
</list>
</class>
<class name="model.SeminarTopic" table="SEMINARTOPIC">
<id name="id" type="long" unsaved-value="null">
<column name="SEMINARTOPIC_ID" not-null="true" />
<generator class="native" />
</id>
<property name="title"><column name="title" not-null="false" /></property>
<property name="description"><column name="description" not-null="false" /></property>
<property name="data"><column name="data" not-null="false" /></property>
<list name="seminarParticipants" lazy="true" cascade="save-update">
<key column="SEMINARTOPIC_ID" />
<index column="I" />
<one-to-many class="model.SeminarParticipant" />
</list>
</class>
<class name="model.Semester" table="SEMESTER">
<id name="id" type="long" unsaved-value="null">
<column name="SEMESTER_ID" not-null="true" />
<generator class="native" />
</id>
<property name="description">
<column name="description" not-null="false" /></property>
<property name="starts"><column name="starts" not-null="false" /></property>
<property name="ends"><column name="ends" not-null="false" /></property>
<set name="seminars" lazy="true" cascade="all">
<key column="SEMESTER_ID" />
<one-to-many class="model.Seminar" />
</set>
</class>
<class name="model.Publication" table="PUBLICATION" polymorphism="implicit">
<id name="id" type="long" unsaved-value="null">
<column name="PUBLICATION_ID" not-null="true" />
<generator class="native" />
</id>
<discriminator column="DiscriminatorType" type="string" />
<property name="title"><column name="title" not-null="false" /></property>
<property name="date"><column name="date" not-null="false" /></property>
<property name="data"><column name="data" not-null="false" /></property>
<set name="members" table="Member_Publication" lazy="true" cascade="save-update">
<key><column name="Publication_ID" not-null="true" /></key>
<many-to-many class="model.Member"><column name="Member_ID" not-null="true" />
</many-to-many>
</set>
</class>
</hibernate-mapping>
Code for model classes
Code:
/*
* Created on 2004-1-27
*/
package model;
/**
* @author Xiaoying Wu
*/
public class Address extends PersistentRoot{
private String street;
private String number;
private Integer zip;
private String city;
private String country;
private Person person;
public Address(){
super();
}
public Address(String s, String n, Integer z, String c, String co){
street = s;
number = n;
zip = z;
city = c;
country = co;
}
public String getStreet() {
return street;
}
public void setStreet(String s){
street = s;
}
public String getNumber() {
return number;
}
public void setNumber(String n){
number = n;
}
public Integer getZip(){
return zip;
}
public void setZip(Integer z){
zip = z;
}
public String getCity() {
return city;
}
public void setCity(String c){
city = c;
}
public String getCountry() {
return country;
}
public void setCountry(String c){
country = c;
}
public Person getPerson(){
return person;
}
public void setPerson(Person p){
person = p;
}
}
Code:
/*
* Created on 2004-1-6
*/
package model;
import java.util.List;
/**
* @author Xiaoying Wu
*/
public class Person extends PersistentRoot{
private Name name;
//private List adresses;
private Cat cat_$CD;
//private Set addresses_$model_Address;
private List sizes_$CL_java_lang_String;
private List phones_$CL_model_Phone;
/** home address */
private Address address_$CD;
//Each Persistent Class must have a constructor without parameter.
public Person(){
super();
}
public Person(Name n){
name = n;
}
public Person(Cat c){
this.cat_$CD = c;
}
public Name getName(){
return name;
}
public void setName(Name n){
this.name = n;
}
//public void setAddresses(Set addresses) {
// addresses_$model_Address = addresses;
//}
//public Set getAddresses() {
// return addresses_$model_Address;
//}
public Cat getCat() {
return cat_$CD;
}
public void setCat(Cat c){
cat_$CD = c;
}
public List getSizes(){
return sizes_$CL_java_lang_String;
}
public void setSizes(List s){
sizes_$CL_java_lang_String = s;
}
public Address getAddress() {
return address_$CD;
}
public void setAddress(Address a){
address_$CD = a;
}
/*
public List getAddresses(){
return addresses;
}
public void setAddresses(List as){
this.addresses = as;
}*/
/*public List getNames(){
return names_$model_Name;
}
public void setNames(List names){
names_$model_Name = names;
}*/
public List getPhones(){
return phones_$CL_model_Phone;
}
public void setPhones(List phones){
phones_$CL_model_Phone = phones;
}
}
Code:
package model;
import java.util.Set;
/**
* @author xiaoying
*
* Persistent Class Member
*/
public class Member extends Person{
//private Name name;
private String email;
private String password;
//private List seminars;
private Set publications_$CL_model_Publication;
public Member(){
super();
}
public Set getPublications() {
return publications_$CL_model_Publication;
}
public void setPublications(Set ps){
this.publications_$CL_model_Publication = ps;
}
//public List getSeminars(){
// return seminars;
//}
//public void setSeminars(List s){
// this.seminars = s;
//}
public String getEmail() {
return email;
}
public String getPassword() {
return password;
}
public void setEmail(String e){
this.email = e;
}
public void setPassword(String p){
this.password = p;
}
/*
public Name getName() {
return name;
}
public void setName(Name n) {
this.name = n;
}
*/
}
Code:
package model;
import java.util.Date;
import java.util.Set;
/**
* @author xiaoying
*/
public class Publication extends PersistentRoot{
private String title;
private Date date;
private String data;
private Set members_$CL_model_Member;
public Publication(){
super();
}
public Set getMembers(){
return members_$CL_model_Member;
}
public void setMembers(Set ms){
this.members_$CL_model_Member = ms;
}
public String getTitle() {
return title;
}
public Date getDate() {
return date;
}
public String getData() {
return data;
}
public void setTitle(String t){
this.title = t;
}
public void setDate(Date d){
this.date = d;
}
public void setData(String b){
this.data = b;
}
}
Code:
/*
* Created on 2004-6-3
*/
package model;
/**
* @author Xiaoying Wu
*/
public class PersistentRoot {
private Long id;
/**
* @return Returns the id.
*/
public Long getId() {
return id;
}
/**
* @param id The id to set.
*/
public void setId(Long id) {
this.id = id;
}
}