Hibernate 查询1+N问题详解


1、1+N简单来说就是,Person和Phone是一对多关系,现在我看看所有手机的信息,对于其属于哪个人不感兴趣,但把lazy设为false(lazy=false),这样就会发出1(查询手机的sql)+N(和所有查询的这些手机相关的Person的查询sql),这样会造成很大的性能开销。

首先列一下会产生1+N问题的代码

Person:

	private int id;
	private String name;
	private int age;

Person.hbm.xml按照常规配置即可


Phone:

	private int id;
	private String type;
	private String description;
	private Person person;  //关联一个用户

Phone.hbm.xml:

<hibernate-mapping>
    <class name="com.akwolf.n_1.Phone" table="PHONE">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="type" type="java.lang.String">
            <column name="TYPE" />
        </property>
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>
        <!-- lazy=false -->
        <many-to-one name="person" class="com.akwolf.n_1.Person" fetch="join" lazy="false">
            <column name="PERSON_ID" />
        </many-to-one>
    </class>
</hibernate-mapping>

为了使效果明显一点,假定一个手机对应一个不同的用户,现在想数据库中添加一些数据:

	@Test
	public void testSave1() {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		Person person;
		Phone phone;

		for (int i = 0; i < 10; i++) {
			person = new Person(0, "zhangsan" + i, 21 + i);

			phone = new Phone(0, "glay" + i, "android智能手机", person);
			session.save(person);
			session.save(phone);
		}
		session.getTransaction().commit();
	}


进行一下下面的查询会看到,控制台输出大量的sql

	@Test
	public void testQuery1() {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		List<Phone> list = (List<Phone>) session.createQuery("from Phone")
				.list();
		for (Phone phone : list) {
			System.out.println(phone.getId()); //对关联的Person并不感兴趣
			// System.out.println(phone.getId()+"---"+phone.getPerson().getName());
		}
		session.getTransaction().commit();
	}



解决方案

1、还是在Phone.hbm.xml中把对于Person关联的映射属性不进行lazy属性的设置,默认为lazy加载

<hibernate-mapping>
    <class name="com.akwolf.n_1.Phone" table="PHONE">
        <id name="id" type="int">
            <column name="ID" />
            <generator class="native" />
        </id>
        <property name="type" type="java.lang.String">
            <column name="TYPE" />
        </property>
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>
        <!-- lazy=true -->
        <many-to-one name="person" class="com.akwolf.n_1.Person" fetch="join">
            <column name="PERSON_ID" />
        </many-to-one>
    </class>
</hibernate-mapping>

2、在lazy=false的情况下,在hql中使用join fetch进行查询(session.createCriteria就是采用连接查询的方式),如:

	@Test
	public void testQuery2() {
		Session session = HibernateUtil.getSessionFactory().getCurrentSession();
		session.beginTransaction();
		List<Phone> list = (List<Phone>) session.createQuery(
				"from Phone p left join fetch p.person per").list();
		for (Phone phone : list) {
			// System.out.println(phone.getId());
			System.out.println(phone.getId() + "---"
					+ phone.getPerson().getName());
		}
		session.getTransaction().commit();
	}

3、对于在Person中设置batch-size应该不算是一种解决方案,对于海量的数据,设置的一些batch-size对于大体来说是无关痛痒的。

ok,这就是小弟看视频对于1+N问题的一点理解,有理解更为深刻的大虾不吝赐教。。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值