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

来源:互联网 发布:淘宝发货地址不是买家 编辑:程序博客网 时间:2024/05/29 04:23

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

数据库脚本:

 

create table student(id varchar(32primary key,
                     team_id 
varchar(32),
                     name 
varchar(32),
                     cardid 
varchar(32),
                     age 
int);

create table team(id varchar(32primary 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
&amp;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"

原创粉丝点击