ManyToOne的xml配置 及 解决N+1问题



一: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














  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值