您的位置:首页 > 其它

Hibernate级联操作Cascade学之---save-update

2007-12-04 14:50 666 查看
所在cascade,就是说我在更新一方的时候,可以根据这一方对象之间的关联关系,去对被关联方进行持久化,比如说Team和Student之间的1对多关系,使用cascade,可以在team方维护其持有的student集合时,自动对其新增,修改,删除的student对象进行持久化,而没必要显示的进行session.save(student)操作

数据库脚本:




create table student(id varchar(32) primary key,


team_id varchar(32),


name varchar(32),


cardid varchar(32),


age int);




create table team(id varchar(32) primary key,


team_id varchar(32),


teamname varchar(32));







insert into team values("1","1","team1");


insert into student values("1","1","stu1","20070101",22);


insert into student values("2","1","stu2","20070102",23);





持久化JavaBean




package Cascade.saveUpdate;








public class Student ...{


private String id;


private String cardid;


private String name;


private int age;


private Team team;




public String getId() ...{


return id;


}




public void setId(String id) ...{


this.id = id;


}




public String getCardid() ...{


return cardid;


}




public void setCardid(String cardid) ...{


this.cardid = cardid;


}




public String getName() ...{


return name;


}




public void setName(String name) ...{


this.name = name;


}




public int getAge() ...{


return age;


}




public void setAge(int age) ...{


this.age = age;


}






public Team getTeam() ...{


return team;


}




public void setTeam(Team team) ...{


this.team = team;


}


}






package Cascade.saveUpdate;






import java.util.HashSet;


import java.util.Set;






public class Team ...{


private String id;


private Set students=new HashSet();


private String teamName;




public String getId() ...{


return id;


}




public void setId(String id) ...{


this.id = id;


}




public Set getStudents() ...{


return students;


}




public void setStudents(Set students) ...{


this.students = students;


}




public String getTeamName() ...{


return teamName;


}




public void setTeamName(String teamName) ...{


this.teamName = teamName;


}






}





Hibernate.cfg.xml




<?xml version='1.0' encoding='UTF-8'?>


<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"


"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">




<!-- Generated by MyEclipse Hibernate Tools. -->


<hibernate-configuration>




<session-factory>


<property name="connection.username">root</property>


<property name="connection.url">


jdbc:mysql://localhost:3306/schoolproject?characterEncoding=gb2312&useUnicode=true


</property>


<property name="dialect">


org.hibernate.dialect.MySQLDialect


</property>


<property name="myeclipse.connection.profile">mysql</property>


<property name="connection.password">1234</property>


<property name="connection.driver_class">


com.mysql.jdbc.Driver


</property>


<property name="hibernate.dialect">


org.hibernate.dialect.MySQLDialect


</property>


<property name="hibernate.show_sql">true</property>


<property name="current_session_context_class">thread</property>


<property name="jdbc.batch_size">15</property>


<mapping resource="Cascade/saveUpdate/Student.hbm.xml" />


<mapping resource="Cascade/saveUpdate/Team.hbm.xml" />








</session-factory>




</hibernate-configuration>



Student.hbm.xml




<?xml version="1.0" encoding="utf-8"?>


<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"


"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<!--


Mapping file autogenerated by MyEclipse - Hibernate Tools


-->


<hibernate-mapping>


<class name="Cascade.saveUpdate.Student" table="student">


<id name="id" unsaved-value="null">


<generator class="uuid.hex"></generator>


</id>


<property name="cardid" type="string"/>


<property name="name" type="string"/>


<property name="age" type="int"/>


<many-to-one name="team"


column="team_id"


class="Cascade.saveUpdate.Team"


lazy="no-proxy">


</many-to-one>


</class>




</hibernate-mapping>





Team.hbm.xml 这里先配置成cascade="none"


<?xml version="1.0" encoding="utf-8"?>


<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"


"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<!--


Mapping file autogenerated by MyEclipse - Hibernate Tools


-->


<hibernate-mapping>


<class name="Cascade.saveUpdate.Team" table="team" lazy="true">


<id name="id" column="id">


<generator class="uuid.hex"></generator>


</id>


<property name="teamName" column="teamname"></property>





<set name="students" lazy="true" inverse="false" cascade="none">


<key column="team_id"></key>


<one-to-many class="Cascade.saveUpdate.Student"/>


</set>


</class>


</hibernate-mapping>





测试代码:




package Cascade.saveUpdate;






import java.io.File;




import org.hibernate.Session;


import org.hibernate.SessionFactory;


import org.hibernate.Transaction;


import org.hibernate.cfg.Configuration;






public class Test ...{








public static void main(String[] args) ...{




String filePath=System.getProperty("user.dir")+File.separator+"src/Cascade/saveUpdate"+File.separator+"hibernate.cfg.xml";


File file=new File(filePath);


System.out.println(filePath);


SessionFactory sessionFactory=new Configuration().configure(file).buildSessionFactory();


Session session=sessionFactory.openSession();


Transaction t=session.beginTransaction();


Student newStu=new Student(); //建立一个student对象,瞬态


newStu.setCardid("12345");


newStu.setAge(22);


newStu.setName("newStu");


Team team=(Team)session.get(Team.class, "1");//获得team对象


Student removeStu=(Student)session.get(Student.class,"1");//获得需要删除的stu对象


team.getStudents().add(newStu); //增加student到team持有的student集合


team.getStudents().remove(removeStu); //删除student到team持有的student集合


t.commit();





}




}





运行代码,结果如下:

Hibernate: select team0_.id as id1_0_, team0_.teamname as teamname1_0_ from team team0_ where team0_.id=?

Hibernate: select student0_.id as id0_0_, student0_.cardid as cardid0_0_, student0_.name as name0_0_, student0_.age as age0_0_, student0_.team_id as team5_0_0_ from student student0_ where student0_.id=?
Hibernate: select students0_.team_id as team5_1_, students0_.id as id1_, students0_.id as id0_0_, students0_.cardid as cardid0_0_, students0_.name as name0_0_, students0_.age as age0_0_, students0_.team_id as team5_0_0_ from student students0_ where students0_.team_id=?

Hibernate: update student set team_id=null where team_id=? and id=?
Hibernate: update student set team_id=? where id=?

Exception in thread "main" org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: Cascade.saveUpdate.Student
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:219)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:397)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:78)
at org.hibernate.persister.collection.AbstractCollectionPersister.writeElement(AbstractCollectionPersister.java:755)
at org.hibernate.persister.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1364)
at org.hibernate.action.CollectionUpdateAction.execute(CollectionUpdateAction.java:56)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:248)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:232)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:142)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
at Cascade.saveUpdate.Test.main(Test.java:30)

可以看到红色的异常,提示没有对象引用,是因为我们没有显示的调用session.save(newStu)又没有设置team端的cascade

如果代码改成session.save(newStu); team.getStudents().add(newStu)就不会有任何问题了



下面,我们看下如果运用cascade="save-update"修正上面的错误,首先修改Team.hbm.xml

注意:cascade="saveupdate"和inverse="false"必须同时设置,才能让team维护级联关系,如果inverse="true"(不让Team维护关系,哪cascad设置也不会有任何作用,虽然可以新插入一条学生的记录,但其team_id为null,无法实现引用关系),如下图数据库表:






<?xml version="1.0" encoding="utf-8"?>


<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"


"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">


<!--


Mapping file autogenerated by MyEclipse - Hibernate Tools


-->


<hibernate-mapping>


<class name="Cascade.saveUpdate.Team" table="team" lazy="true">


<id name="id" column="id">


<generator class="uuid.hex"></generator>


</id>


<property name="teamName" column="teamname"></property>





<set name="students" lazy="true" inverse="false" cascade="save-update">


<key column="team_id"></key>


<one-to-many class="Cascade.saveUpdate.Student"/>


</set>


</class>


</hibernate-mapping>





重新运行代码:

Hibernate: select team0_.id as id1_0_, team0_.teamname as teamname1_0_ from team team0_ where team0_.id=?
Hibernate: select student0_.id as id0_0_, student0_.cardid as cardid0_0_, student0_.name as name0_0_, student0_.age as age0_0_, student0_.team_id as team5_0_0_ from student student0_ where student0_.id=?
Hibernate: select students0_.team_id as team5_1_, students0_.id as id1_, students0_.id as id0_0_, students0_.cardid as cardid0_0_, students0_.name as name0_0_, students0_.age as age0_0_, students0_.team_id as team5_0_0_ from student students0_ where students0_.team_id=?

Hibernate: insert into student (cardid, name, age, team_id, id) values (?, ?, ?, ?, ?)
Hibernate: update student set team_id=null where team_id=? and id=?
Hibernate: update student set team_id=? where id=?

可以看到,红色的部分插入了新数据,并使用update更新其team_id字段,维护约束关系



不过,需要主意的是,使用cascade="save-update"删除集合中的数据时候,不能真正的从数据库中删除记录,只是简单的讲其关联约束字段(如team_id)设置为null,被删除的对象还是保留在session缓存中,还是可以通过
removStu.setName("111")改变对象并进行持久化,如果需要使用这种方式删除对象并持久化,可以设置
cascade="all-delete-orphan"
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: