Hibernate抓取策略

原创
2016/10/22 11:42
阅读数 145

6、抓取策略:抓取策略主要是指获取连接对象的策略。

    6.1、基于XML的抓取

    1.1、基于XML抓取many-to-one

			session = HibernateUtil.openSession();
			/**
			 * 默认情况会发出3条SQL语句,一条取Student,一条取Classroom,一条取Special
			 * many-to-one的默认情况,使用的是延迟加载
			 */
			Student stu = session.load(Student.class, 1);
			System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());

    1.2、设置fetch="join"

			session = HibernateUtil.openSession();
			/**
			 * 默认情况会发出3条SQL语句,一条取Student,一条取Classroom,一条取Special
			 * 通过设置XML中的<many-to-one name="classroom" column="cid" fetch="join"/>
			 * 可以完成对抓取的设置,只会发出一条SQL语句
			 */
			Student stu = session.load(Student.class, 1);
			System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
		<!-- 设置了fetch="join"之后,会连接查询将对象加载出来 -->
		<many-to-one name="classroom" column="cid" fetch="join"/>

    存在问题:延迟加载失效

			session = HibernateUtil.openSession();
			/**
			 * 使用fetch="join"虽然可以将关联对象抓取,但是如果不使用关联对象也会一并查询出来
			 * 这样会占用相应的内存
			 */
			Student stu = session.load(Student.class, 1);
			//延迟加载就失效
			System.out.println(stu.getName());

    1.3、但是fetch="join"无法抓取HQL中的list,如果需要抓取HQL中的list有两种方法:

        ·设置one这一端对象的batch-size,此时会通过in的语句来加载多条数据。

<hibernate-mapping package="org.pm.hibernate.model">
	<!-- 设置batch-size="20",在抓取Classroom的时候,会一下抓取20Classroom的记录 -->
    <class name="Classroom" table="t_classroom" batch-size="20">
        <id name="id">
            <generator class="native"/>
        </id>
			session = HibernateUtil.openSession();
			/**
			 * 在XML中配置了fetch="join"仅仅只是对load的对象有用,对HQL中查询的对象无用,
			 * 所以此时会发出查询班级的SQL,解决这个SQL的问题有两种方案,
			 * 一种是设置对象的抓取的batch-size
			 * 另一种方案在HQL中指定抓取
			 */
			List<Student> stus = session.createQuery("from Student", Student.class).getResultList();
			for(Student stu:stus) {
				System.out.println(stu.getName()+","+stu.getClassroom().getName());
			}

        ·在HQL语句中写预抓取(特别注意:使用预抓取不支持count(*)查询)

			session = HibernateUtil.openSession();
			/**
			 * 在XML中配置了fetch="join"仅仅只是对load的对象有用,对HQL中查询的对象无用,
			 * 所以此时会发出查询班级的SQL,解决这个SQL的问题有两种方案,
			 * 一种是设置对象的抓取的batch-size
			 * 另一种方案在HQL中指定抓取,通过在HQL中添加fetch关键字完成抓取
			 * 特别注意:如果使用了join fetch就无法使用count(*)
			 */
			List<Student> stus = session.createQuery("select stu from "
					+ "Student stu join fetch stu.classroom", Student.class).getResultList();
			for(Student stu:stus) {
				System.out.println(stu.getName()+","+stu.getClassroom().getName());
			}

    1.4、集合抓取

		<!-- 设置fetch="subselect",对于list查询它会根据查询的结果来完成对对象的子查询 -->
		<set name="stus" inverse="true" lazy="extra" fetch="subselect">
			<key column="cid"/>
			<one-to-many class="Student"/>
		</set>
			session = HibernateUtil.openSession();
			List<Classroom> clas = session.createQuery("from Classroom", Classroom.class).getResultList();
			for(Classroom cla:clas) {
				System.out.println(cla.getName());
				/*
				 * 抓取集合,默认是select,此时会为每一个班的学生发出sql
				 * 对于通过HQL取班级列表并且获取相应的学生列表时,fetch="join"就无效了
				 * 第一种方案可以设置set的batch-size来完成批量的抓取
				 * 第二种方案可以设置fetch=subselect,使用subselect会完成根据查询出来的班级
				 * 进行一次对学生对象的子查询
				 */
				for(Student stu:cla.getStus()) {
					System.out.print(stu.getName());
				}
			}

    对于集合抓取而言,有三种设置方式:select(默认),join,subselect。

    其中在查询单个对象时,select和subselect完全一样,都是在需要查询集合对象时才发出sql,但是join会
    使用连接查询。

    在查询列表对象时,select和join一样(可以通过设置set的batch-size设置抓取的数量)

最佳实践:很多情况不会设置one-to-many,如果要设置one-to-many可以设置为subselect。

    6.2、基于Annotation的抓取

    1、基于Annotation的many-to-one

			session = HibernateUtil.openSession();
			/**
			 * 对于Annotation的配置而言,默认就是基于join的抓取的,所以只会发出1条SQL
			 */
			Student stu = session.load(Student.class, 1);
			System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+stu.getClassroom().getSpecial().getName());
			session = HibernateUtil.openSession();
			/**
			 * 基于Annotation的配置没有延迟加载,此时会把所有的关联对象查询出来,发出大量的SQL语句
			 */
			List<Student> stus = session.createQuery("from Student", Student.class).getResultList();
			for(Student stu:stus) {
				System.out.println(stu.getName()+","+stu.getClassroom().getName());
			}
	@ManyToOne(fetch=FetchType.EAGER) //LAZY就是XML中select,EAGER就表示XML中的join
	@JoinColumn(name="cid")
	public Classroom getClassroom() {
		return classroom;
	}
	public void setClassroom(Classroom classroom) {
		this.classroom = classroom;
	}
			session = HibernateUtil.openSession();
			/**
			 * 基于Annotation,由于many-to-one的默认抓取策略是EAGER的,所以当抓取Classroom
			 * 时会自动发出多条SQL去查询相应的Special,此时可以通过join fetch继续完成对关联的
			 * 抓取,或者直接将关联对象的fetch设置为LAZY,但是使用LAZY所带来的问题是在查询
			 * 关联对象时需要发出相应的SQL,很多时候也会影响效率
			 */
			List<Student> stus = session.createQuery("select stu from "
					+ "Student stu join fetch stu.classroom cla join fetch cla.special", Student.class).getResultList();
			for(Student stu:stus) {
				System.out.println(stu.getName()+","+stu.getClassroom().getName());
			}

    可以使用@BatchSize

@Entity
@Table(name="t_classroom")
@BatchSize(size=20)
public class Classroom {
	private int id;
	private String name;
	private int grade;
	private Set<Student> stus;
	private Special special;

    2、集合抓取

	@OneToMany(mappedBy="classroom")
	@LazyCollection(LazyCollectionOption.EXTRA)
	@Fetch(FetchMode.SUBSELECT) //在Annotation中需要通过这种方式才能设置subselect
	public Set<Student> getStus() {
		return stus;
	}
	public void setStus(Set<Student> stus) {
		this.stus = stus;
	}
	
	@ManyToOne(fetch=FetchType.LAZY)
	@JoinColumn(name="spe_id")
	public Special getSpecial() {

 

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部