hibernate一对多 多对一 的 双向关联


hibernate中  听说一对多 还有多对一 用的比较多,于是作为菜鸟的我 准备先从这个开始下刀学习-。-


下面是我看到的一篇很好的文章 讲述的很清晰很好,尤其是对生成的sql做了对比,设计到 hibernate以后的优化,要用好hibernate就要从这里开始=、=


双向关联:

 

以上多对一,一对多的关系都是单向关联,也就是一方联系到另一方,而另一方不知道自己被关联。

 

cascade:设置级联

  sava-update:级联保存、更新

  delete:级联删除

  none:不级联,默认值

  all:级联保存、更新、删除

 

 

inverse:在映射一对多关系时,一般将该属性设置为true,表示表间的关联关系由一方设置,减少update语句,提高性能。

如果上方都意识到另一方的存在,则形成双向关联。现将上面的代码改写如下:

 

User类中追加Room类型的字段:

 

package com.hb3.pack_20.model; 

 

public class User { 

 

    private Integer id; 

    private String name; 

    private Room room; 

     

    public Room getRoom() { 

        return room; 

    } 

 

    public void setRoom(Room room) { 

        this.room = room; 

    } 

 

    public User() { 

    } 

 

    public Integer getId() { 

        return id; 

    } 

    public void setId(Integer id) { 

        this.id = id; 

    } 

    public String getName() { 

        return name; 

    } 

    public void setName(String name) { 

        this.name = name; 

    } 

}

User.hbm.xml中也同样追加关于Room的信息:

 

<?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"> 

 

<hibernate-mapping>  

 

    <class name="com.hb3.pack_20.model.User" table="user"> 

     

        <id name="id" column="id" type="java.lang.Integer">  

            <generator class="native"/>  

        </id>  

 

        <property name="name" column="name" type="java.lang.String"/>  

         

        <many-to-one name="room"  

                     column="room_id"  

                     class="com.hb3.pack_20.model.Room" 

                     cascade="save-update" 

                     outer-join="true"/>  

         

    </class>  

 

</hibernate-mapping>

这里我们将Room.hbm.xml文件里setcascade属性也设为save-update

 

<?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"> 

 

<hibernate-mapping> 

 

    <class name="com.hb3.pack_20.model.Room" table="room">  

     

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

            <generator class="native"/>  

        </id>  

         

        <property name="address"  

                  column="address"  

                  type="java.lang.String"/>  

                   

        <set name="users" table="user" cascade="save-update"> 

            <key column="room_id"/> 

            <one-to-many class="com.hb3.pack_20.model.User"/> 

        </set> 

         

    </class>  

</hibernate-mapping>

这样我们可以用多对一的方式来维持管理:

 

package com.hb3.pack_20; 

 

import org.hibernate.Session; 

import org.hibernate.SessionFactory; 

import org.hibernate.Transaction; 

import org.hibernate.cfg.Configuration; 

 

import com.hb3.pack_20.model.Room; 

import com.hb3.pack_20.model.User; 

 

public class BusinessService { 

 

    public static void main(String[] args) { 

         

        Configuration config = new Configuration().configure(); 

        SessionFactory sessionFactory = config.buildSessionFactory();       

        Session session = sessionFactory.openSession(); 

 

         

        User user1 = new User(); 

        user1.setName("chenyan");  

                 

        User user2 = new User();  

        user2.setName("shenbin");  

 

        Room room1 = new Room();  

        room1.setAddress("NTU-M8-419"); 

 

        user1.setRoom(room1); 

        user2.setRoom(room1); 

                 

        Transaction tx = session.beginTransaction();      

        session.save(user1); 

        session.save(user2); 

        tx.commit(); 

 

 

        session.close(); 

        sessionFactory.close(); 

    } 

}

或者反过来由一对多的方式来维持关系:

 

package com.hb3.pack_20; 

 

import java.util.HashSet; 

 

import org.hibernate.Session; 

import org.hibernate.SessionFactory; 

import org.hibernate.Transaction; 

import org.hibernate.cfg.Configuration; 

 

import com.hb3.pack_20.model.Room; 

import com.hb3.pack_20.model.User; 

 

public class BusinessService { 

 

    public static void main(String[] args) { 

         

        Configuration config = new Configuration().configure(); 

        SessionFactory sessionFactory = config.buildSessionFactory();       

        Session session = sessionFactory.openSession(); 

 

         

        User user1 = new User(); 

        user1.setName("chenyan");  

                 

        User user2 = new User();  

        user2.setName("shenbin");  

 

        Room room1 = new Room();  

        room1.setUsers(new HashSet<User>()); 

        room1.setAddress("NTU-M8-419"); 

        room1.addUser(user1); 

        room1.addUser(user2); 

                 

        Transaction tx = session.beginTransaction();   

        session.save(room1);  

        tx.commit(); 

 

 

        session.close(); 

        sessionFactory.close(); 

    } 

}

但是一对多的方式来维持的话,先看一下生成的SQL文:

 

Hibernate: insert into room (address) values (?)

Hibernate: insert into user (name, room_id) values (?, ?)

Hibernate: insert into user (name, room_id) values (?, ?)

Hibernate: update user set room_id=? where id=?

Hibernate: update user set room_id=? where id=?

 

 

 

可见,如果把一的一方Room作为主控方,多的一方User因为不知道Roomroom_id是多少,所以必须等RoomUser存储之后再更新room_id。所以在多对一,一对多形成双向关联的时候,应该把控制权交给多的一方,这样比较有效率。理由很简单,就像在公司里一样,老板记住所有员工的名字来得快,还是每个员工记住老板的名字来得快。

 

 

 

基于这个理由,我们对Room.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"> 

 

<hibernate-mapping> 

 

    <class name="com.hb3.pack_20.model.Room" table="room">  

     

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

            <generator class="native"/>  

        </id>  

         

        <property name="address"  

                  column="address"  

                  type="java.lang.String"/>  

                   

        <set name="users" table="user" cascade="save-update" inverse="true"> 

            <key column="room_id"/> 

            <one-to-many class="com.hb3.pack_20.model.User"/> 

        </set> 

         

    </class>  

</hibernate-mapping>

如此控制权就交给了多的一方。当直接存储一的一方前,必须让多的一方意识的一的一方的存在。

 

package com.hb3.pack_20; 

 

import java.io.IOException; 

import java.sql.SQLException; 

import java.util.HashSet; 

 

import org.hibernate.Session; 

import org.hibernate.SessionFactory; 

import org.hibernate.Transaction; 

import org.hibernate.cfg.Configuration; 

 

import com.hb3.pack_20.model.Room; 

import com.hb3.pack_20.model.User; 

 

public class BusinessService { 

 

    public static void main(String[] args) throws IOException, SQLException { 

         

        Configuration config = new Configuration().configure(); 

        SessionFactory sessionFactory = config.buildSessionFactory();       

        Session session = sessionFactory.openSession(); 

 

         

        User user1 = new User(); 

        user1.setName("bush");  

                 

        User user2 = new User();  

        user2.setName("caterpillar");  

 

        Room room1 = new Room();  

        room1.setUsers(new HashSet<User>()); 

        room1.setAddress("NTU-M8-419"); 

        room1.addUser(user1); 

        room1.addUser(user2); 

 

        //多方必须认识到单方的存在 

        user1.setRoom(room1); 

        user2.setRoom(room1); 

                 

        Transaction tx = session.beginTransaction();      

        session.save(room1);  

        tx.commit(); 

 

 

        session.close(); 

        sessionFactory.close(); 

    } 

}

此时生成的SQL文为:

 

Hibernate: insert into room (address) values (?)

Hibernate: insert into user (name, room_id) values (?, ?)

Hibernate: insert into user (name, room_id) values (?, ?)

 

从而提高了效率。

 

 

 

如果把代码中user1.setRoom(room1);user2.setRoom(room1);2行移去,你会发现数据库中room_id的值为null。这个结果就好比在多对一的关系中没有分配给User一个Room,那么理所当然room_id的值为null了。

 

 

 

HIBERNATE一对多配置实例

1. 环境:假定班级和学生是一对多的关系,班级是一,学生是多,对应表格分别是:zlass ,student

2. 创建ZlassStudent对象

//Zlass对象---------------------------------------------------------

    public class Zlass{

 

 private String class_id;

 private String class_name;

 private java.util.Set students;

 

 public void setId(String id){

    this.class_id = id;

 }

 

 public void setClassName(String className){

    this.class_name = className;

 }

 

 public void setStudents(java.util.Set students){

    this.students = students;

 }

 

 public String getId(){

    return class_id;

 }

 

 public String getClassName(){

    return class_name;

 }

 

 public java.util.Set getStudents(){

    return students;

 }

 

}

 

//学生对象

public class Student{

       private String student_id;

       private String name;

       private Address address;

       private java.util.Set events;

       private java.util.Set lessons;

       private Zlass zlass;

       

       public Zlass getZlass(){

              return zlass;

       }

 

       public String getStudentId(){

              return student_id;

       }

       

       public String getName(){

              return name;

       }

       

       public Address getAddress(){

              return address;

       }

       

       public java.util.Set getEvents(){

              return events;

       }

       

       public java.util.Set getLessons(){

              return lessons;

       }

 

       public void setZlass(Zlass zlass){

              this.zlass = zlass;

       }

       

       public void setStudentId(String studentId){

              this.student_id = studentId;

       }

       

       public void setName(String name){

              this.name = name;

       }

       

       public void setAddress(Address address){

              this.address = address;

       }

       

       public void setEvents(java.util.Set events){

              this.events =events;

       }

       

       public void setLessons(java.util.Set lessons){

              this.lessons = lessons;

       }

       

}

 

 

//配置文件

//----------Zlass.hbm.xml---------------

<hibernate-mapping package="com.softWork.school">

 <class name="Zlass" table="class">

    <id name="id" column="id" type="string" length="20">

      <generator class="assigned"/>

    </id>

    <property name="className" column="class_name" type="string" length="200"/>

    

    <set name="students" inverse="false" cascade="all">

      <key column="class_id"/>

      <one-to-many class="Student"/>

    </set>

 </class>

</hibernate-mapping>

//-------------Student.hbm.xml---------------

<hibernate-mapping package="com.softWork.school">

 <class name="Student" table="student">

    <id name="studentId" column="student_id" type="string" length="20">

      <generator class="assigned"/>

    </id>

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

    <component name="address" class="Address">

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

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

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

    </component>

    <set name="events" inverse="false" cascade="all">

      <key column="student_id"></key>

      <one-to-many class="Event"></one-to-many>

    </set>

    

    <set name="lessons" table="student_lesson">

      <key column="student_id"/>

      <many-to-many class="Lesson" column="lesson_id" />

    </set>

    <many-to-one name="zlass" column="class_id" class="Zlass"/>

 </class>

</hibernate-mapping>

 

以上使用的是班级一端维护关系,并级连操作

 

3. 使用级连操作数据

1) 新增班级

       Zlass zlass = new Zlass();

       zlass.setId("971002");

       zlass.setClassName("机制97-1");

session.saveOrUpdate(zlass);

2) 为班级新增学生

主动端操作:

      Zlass zlass = (Zlass)session.load(Zlass.class,"971002");

      Student student = new Student();

      student.setStudentId("005");

      student.setName("没名");

      zlass.getStudents().add(student);

      session.saveOrUpdate(zlass);

被动端操作:

      Zlass zlass = (Zlass)session.load(Zlass.class,"971002");

      Student student = new Student();

      student.setStudentId("006");

      student.setName("006");

      student.setZlass(zlass);

session.saveOrUpdate(student);

3) 删除学生资料

主动端操作:

主动端除非删除自己,并设置了级连才能删除子对象,否则无法完成

//-----以下代码将只删除两者之间的关系,即将学生的class_id设置为null-----

Zlass zlass = (Zlass)session.load(Zlass.class,"971001");

java.util.Iterator iterator = zlass.getStudents().iterator();

      if (iterator.hasNext())

        zlass.getStudents().remove(iterator.next());

      session.saveOrUpdate(zlass);

被动端操作:

              Student student = (Student)session.load(Student.class,"002");

session.delete(student);

4) 修改学生资料

通过班级修改学生资料

 

Zlass zlass = (Zlass)session.load(Zlass.class,"971002");

      java.util.Iterator iterator = zlass.getStudents().iterator();

      if (iterator.hasNext()){

        Student student = (Student)iterator.next();

        student.setName("名字已修改");

      }

session.saveOrUpdate(zlass);

 

读取返回的Set型数据:

java.util.Set set = student.getEvents();

java.util.Iterator iterator = set.iterator();

while(iterator.hasNext()){

evt = (Event)iterator.next();

System.out.println(evt.getContent());

System.out.println(evt.getDate().toString());

}

 

4. 注意:

如果需要从多放引导到一方,需要在一方配置文件中设置inverse=true”参数,以设定一方到多方的设定是逆向映射,对关联的逆向端所做的修改将不会被持久化。

Inverse=true”的表示两个实体的关系由对方去维护。

5. 推荐配置,一般的将”一”这一端设置为inverse=false”,cascade=all” ,这样一般的操作只需要在”一”这一端操作,此适合于标志性一对多的情况,如销售单和销售明细

如果是非标志性一对多,则一般的将inverse=false,cascade=none,这样关系永远在主动一端进行控制

示范:假如AB是一对多,当A中原来有B1B2B3,当A中的集合中只包含B1B2时,那么BB3的外码将被设置为NULL,这个是CASCADE=FALSE”的情况下的结果

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值