一:ManyToOne的cfg.xml配置
1.实体,省略setter&getter
public class User implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;// 编号
private String account;// 用户名
private String password;
private Dept dept;//多个人属于一个部门, 所以是many(用户) to one(部门)
public class Dept implements Serializable{
public Integer deptno;//部门编号
public String deptname;//部门名称等等...如果是要双向连接 这要多写一个Set<User>
2.xml配置
ManyToOne肯定是要配置在"多"的一方 ,
因为User表中每一行最后, 多存一个部门编号就可以了 .要是"一"的一行保存需要很多行数据才能反映全部关联关系.(两头都有那就是冗余了)
<hibernate-mapping package="com.rt.model">
<class name="User" table="t_user">
<id name="id" type="java.lang.Integer" length="10">
<generator class="assigned"/>
</id>
<property name="account" type="string" not-null="true" length="45"/>
<property name="password" type="string" not-null="true" length="45"/>
<!--<property name="admin" type="com.rt.model.Admin" />
<property name="dept" type="com.rt.model.Dept" />-->
<!-- 多对一映射用户 -->
<!-- 这不配置lazy且不配置fetch的话, 就已经不存在N+1问题了, 后边具体分析-->
<many-to-one name="dept"
column="deptno"
class="com.rt.model.Dept"
not-null="true"
cascade="none"
/>
</class>
</hibernate-mapping>
作为"一"这一端, 可以不做任何配置, 他不需要知道具体哪些User要关联自己
<hibernate-mapping package="com.rt.model">
<class name="Dept" table="t_dept">
<id name="deptno" type="java.lang.Integer" length="10">
</id>
<property name="deptname" not-null="true" length="45"/>
</class>
3.自动生成表
<property name="hbm2ddl.auto">update</property>
二:N+1问题
试验了好多次, 先写清楚结论再分析:
1.结论
这样配置就没有N+1问题,
<many-to-one name="dept"
column="deptno"
class="com.rt.model.Dept"
not-null="true"
cascade="none"
/>
如果加上
fetch="join"
仍然没有N+1问题
2.分析一下:
Hibernate3已经默认把lazy配置设置成了true ,所以不手动改掉的话 就已经是延迟加载了. 所以就是用延迟加载的方式解决了N+1
fetch是用另一种思路解决N+1的: join就是查表时候 ,一次性把所有有关的项目都查出来, 既然一次性都查全了 就业不用N+1了 . 所以fetch更适合配上缓存用.
lazy 参数值常见有 false 和 true,Hibernate3 映射文件中默认lazy = true ;
fetch 指定了关联对象抓取的方式,参数值常见是select和join,默认是select, select方式先查询主对象,再根据关联外键,每一个对象发一个select查询,获取关联的对象,形成了n+1次查询;而join方式,是left outer join查询,主对象和关联对象用一句外键关联的sql同时查询出来,不会形成多次查询。
在映射文件中,不同的组合会使用不同的查询:
1、lazy="true" fetch = "select" ,使用延迟策略,开始只查询出主对象,关联对象不会查询,只有当用到的时候才会发出sql语句去查询 ;
2、lazy="false" fetch = "select" ,没有用延迟策略,同时查询出主对象和关联对象,产生1+n条sql.
3、lazy="true"或lazy="false" fetch = "join",延迟都不会作用,因为采用的是外连接查询,同时把主对象和关联对象都查询出来了.
另外,在hql查询中,配置文件中设置的join方式是不起作用的,而在其他查询方式如get、criteria等是有效的,使用 select方式;除非在hql中指定join fetch某个关联对象。fetch策略用于get/load一个对象时,如何获取非lazy的对象/集合。 这些参数在Query中无效。
3.测试程序
User u=testDao.findUser(i);
System.out.println("=>" + u.getAccount());
System.out.println("=>" + u.getPassword());
System.out.println("=>" + u.getId());
System.out.println("--111----");
System.out.println("=>" + u.getDept().getDeptname());
System.out.println("--222----");
System.out.println("=>" + u.getAdmin().getPmain());
前三项是User实体内的字段,
后两项是ManyToOne关系关联的, 看下输出SQL语句的顺序就明白了
(1)没有fetch="join"的情况下:
就是lazy形式, 没有用到的就不去查 用到哪个查哪个Hibernate: select user0_.id as id1_0_, user0_.account as account1_0_, user0_.password as password1_0_, user0_.deptno as deptno1_0_, user0_.adminid as adminid1_0_ from t_user user0_ where user0_.id=?
=>tao
=>123456
=>250
--111----
Hibernate: select dept0_.deptno as deptno3_0_, dept0_.deptname as deptname3_0_ from t_dept dept0_ where dept0_.deptno=?
=>10
--222----
Hibernate: select admin0_.adminid as adminid2_0_, admin0_.pmain as pmain2_0_, admin0_.pc1 as pc3_2_0_, admin0_.pc2 as pc4_2_0_ from t_admin admin0_ where admin0_.adminid=?
=>1
(2)有fetch="join"
一次性一条之内全查出来,
Hibernate: select user0_.id as id1_2_, user0_.account as account1_2_, user0_.password as password1_2_, user0_.deptno as deptno1_2_, user0_.adminid as adminid1_2_, dept1_.deptno as deptno3_0_, dept1_.deptname as deptname3_0_, admin2_.adminid as adminid2_1_, admin2_.pmain as pmain2_1_, admin2_.pc1 as pc3_2_1_, admin2_.pc2 as pc4_2_1_ from t_user user0_ inner join t_dept dept1_ on user0_.deptno=dept1_.deptno inner join t_admin admin2_ on user0_.adminid=admin2_.adminid where user0_.id=?
=>tao
=>123456
=>250
--111----
=>10
--222----
=>1