场景:
有三个对象类, Student, IdCard, Team.
Student和IdCard是一对一关系。
而Team和Student是一对多关系。
Student和IdCard的类声明以及映射文件配置和http://alleni123.iteye.com/admin/blogs/1978000这里的类大致一样。 只是Student里面多了一个 private Team team,
以及配置文件里面要加入一个<many-to-one>映射到Team对象。
Team类如下:
public class Team { private String id; private String name; private Set<Student> students; }
Team配置文件:
<class name="Team" table="test_team"> <id name="id" column="id" type="string"> <generator class="uuid"></generator> </id> <property name="name" column="name" type="string"/> <!-- 在一对多的对应关系中,都是让多的一方来维持对应关系,所以在这里设置为true,既由students来维持关系--> <set name="students" [b]lazy="false"[/b] cascade="all" inverse="true"> <key column="team_id"/> <one-to-many class="Student"/> </set> </class>
插入代码:
public class HibernateTeam_1insert { public static void main(String[] args) { Session session=HibernateUtil.openSession(); Team team=new Team(null,"impl_team",null); Student s1=new Student("alleni", null); Student s2=new Student("eline",null); IdCard card1=new IdCard(001, s1); IdCard card2=new IdCard(002,s2); s1.setIdCard(card1); s2.setIdCard(card2); //如果没这两行,便会报错[url]http://alleni123.iteye.com/admin/blogs/1978483[/url] s1.setTeam(team); s2.setTeam(team); //如果没有这两行,student对象将不会和team在数据库中关联,并且不会报错。 为了解决这个问题, 可以在Student映射配置文件中配置not-null=true,如此Hibernate便会让Nullability类执行checkNullability(). team.setStudents(ArraysHelper.asSet(s1,s2)); Transaction tx=session.beginTransaction(); session.save(team); tx.commit(); } }
代码运行后的数据库如下:
=================================================
查询
延迟加载查询
查询代码如下:
Session session=HibernateUtil.openSession(); Team team = (Team) session.load(Team.class,"4028bd814279be81014279be84ff0000" ); System.out.println(team.getName());
Hibernate: select team0_.id as id1_5_0_, team0_.name as name2_5_0_ from test_team team0_ where team0_.id=?
Hibernate: select students0_.team_id as team3_5_2_, students0_.id as id1_4_2_, students0_.id as id1_4_1_, students0_.name as name2_4_1_, students0_.team_id as team3_4_1_, idcard1_.id as id1_1_0_, idcard1_.card_number as card2_1_0_ from test_student students0_ inner join test_idcard idcard1_ on students0_.id=idcard1_.id where students0_.team_id=?
这里Hibernate发出了两条查询语句,第二条我们可以看到很多对象名称,包括student,idcard。
也就是说Hibernate使用了一个inner join查询将所有关联的对象都提取了出来。
之所以会这样, 是因为上面在Team.xml配置文件中,<set>元素的lazy被设置成了false,延迟加载被禁用。
因此即使我们只需要查询team的名字,Hibernate也会使用join方法的SQL来获取所有关联对象的内容。
要解决这个问题, 只要设置Team.xml中的<set>的lazy=true,便能解决。
//Team.xml //<set name="students" lazy="true" cascade="all" inverse="true" fetch="select"> Team team = (Team) session.load(Team.class,"4028bd814279be81014279be84ff0000" ); System.out.println(team.getName()); //执行结果 //Hibernate: select team0_.id as id1_5_0_, team0_.name as name2_5_0_ from test_team team0_ where team0_.id=? //impl_team
这里要注意设置fetch="select",(其实默认就是select)
如果fetch=join,那么即使lazy=true,也还是会通过inner join来进行关联加载。即使这里指查询了team的名称,也会发出一长串join连接的sql语句来查到其它内容。
小知识点:
在Hibernate.cfg.xml中配置property max_fetch_depth的值,可以限制Hibernate在查询时的级联深度, 此方法可以防止Hibernate进行无限止的级联查询,耗费数据库资源。
<property name="hibernate.max_fetch_depth">1</property>
1表示最多进行一级的查询。
这里遇到了一个问题,就是在设置Student和IdCard的延迟加载时,Hibernate没有实现延迟加载。
===============
最后把至今为止hibernate测试的代码传一下。