Hibernate一对多、多对一关联关系的使用

    技术2022-05-19  23

    双向关联:

    Student.hbm.xml

        <class name="model.Student" table="student" lazy="true"

           select-before-update="true"><!--把类和数表关联起来-->

           <id name="id" unsaved-value="null"><!--id的产生方式是uuid.hex-->

               <generator class="uuid.hex" />

           </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="model.Team"

               cascade="none"

               fetch="join"

           /><!--映射班级-->

        </class>

    Team.hbm.xml

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

           <id name="id" unsaved-value="null"><!--id的产生方式是uuid.hex-->

               <generator class="uuid.hex" />

           </id>

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

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

               <key column="team_id" />

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

           </set>

        </class>

    <many-to-one>标签具有column属性,column总是和关联类(对于student类来说,关联类是team)的主键id相对应,因此hibernate会根据student表中的team_id,根据Team表中设置的id列,取出team.id=student.team_id的记录,构造成Team对象返回给Student对象。

    1 不设置inverse标签

    测试类:

    Student newStu=new Student();

               newStu.setCardId("12345");

               session = HibernateUtil.currentSession(); //开启连接

               tx = session.beginTransaction(); //开启事务

               Team team=(Team) session.get(Team.class,"ff80808105416d3b0105416d3eca0002");

               Student removeStudent = (Student)session.get(Student.class, "ff80808105416d3b0105416d3eca0001");

               team.getStudents().add(newStu);

               team.getStudents().remove(removeStudent);

     

    控制台输出结果:

    l  Hibernate: select team0_.id as id2_0_, team0_.teamName as teamName2_0_ from team team0_ where team0_.id=?

    l  Hibernate: select student0_.id as id0_1_, student0_.cardId as cardId0_1_, student0_.name as name0_1_, student0_.age as age0_1_, student0_.team_id as team5_0_1_, team1_.id as id2_0_, team1_.teamName as teamName2_0_ from student student0_ left outer join team team1_ on student0_.team_id=team1_.id where student0_.id=?

    l  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=?

    l  Hibernate: insert into student (cardId, name, age, team_id, id) values (?, ?, ?, ?, ?)

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

    l  Hibernate: update student set team_id=? where id=?

    第五条语句是由team.getStudents().remove(removeStudent);语句引起的,从学生集合中删除一个学生,所以要将学生的team_id 设置为空,由于级联为设置delete-orphan,也就并不发送delete语句删除学生在数据库中的记录。

    第四条语句已经加入了team_id字段,是因为设置了双向关联,但其实插入的值为空。

    第六条语句来将此新添学生的team_id 设置为一个正确的值。

    这个例子新添加学生的过程是先插入后更新。

     

    对测试类进行一下修改,

    测试类:(学生添加班级方式)

        Student newStu=new Student();

               newStu.setCardId("12345");

               session = HibernateUtil.currentSession(); //开启连接

               tx = session.beginTransaction(); //开启事务

               Team team=(Team) session.get(Team.class,"ff80808105416d3b0105416d3eca0002");

               newStu.setTeam(team);

               session.save(newStu);

    控制台输出如下:

    Hibernate: select team0_.id as id2_0_, team0_.teamName as teamName2_0_ from team team0_ where team0_.id=?

    Hibernate: insert into student (cardId, name, age, team_id, id) values (?, ?, ?, ?, ?)

     

     

    2 设置inverse标签为true

    Team.hbm.xml

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

           <id name="id" unsaved-value="null"><!--id的产生方式是uuid.hex-->

               <generator class="uuid.hex" />

           </id>

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

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

               <key column="team_id" />

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

           </set>

        </class>

     

    测试类:(班级添加学生)

      Student newStu=new Student();

               newStu.setCardId("12345");

               session = HibernateUtil.currentSession(); //开启连接

               tx = session.beginTransaction(); //开启事务

               Team team=(Team) session.get(Team.class,"ff80808105416d3b0105416d3eca0002");

               team.getStudents().add(newStu);

    控制台输出:

    l  Hibernate: select team0_.id as id2_0_, team0_.teamName as teamName2_0_ from team team0_ where team0_.id=?

    l  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=?

    l  Hibernate: insert into student (cardId, name, age, team_id, id) values (?, ?, ?, ?, ?)

    测试类在执行完add(newStu)之后并没有调用Sessionupdate()方法更新Team对象,是因为Team对象已经是持久化对象,在清理缓存时会自动调用update()方法。

    第一条:get()方法立即加载Team对象

    第二条:team.getStudents()方法加载此Team中所有的学生对象

    第三条:插入新的学生记录

     

    学生添加班级的性能会好一些,因为班级添加学生时候要加载所有的学生对象,有点多余

    此时新建学生的team_id值为null,由于在Team.hbm.xml中设置了inverse=true”,teamstudent之间的关系由student来维护,因此当team掌握维护权时(inverse=false”或默认状态),他负责将自己的id告诉student,然后hibernate发送update语句去更新记录。但是现在设置了inverse=true”,维护权在student手中,于是hibernate不再发送update语句,而是由student自己去取得team_id,而这个取得team_id的动作,其实就是完成一个“学生添加班级”的动作,也就是语句newStu.setTeam(team)(将此句话加入测试类),两次运行程序控制台的输出相同,但是数据库的结果不相同,新添加的学生得到了正确的team_id值。

     


    最新回复(0)