Hibernate抓取策略

六、抓取策略:抓取策略主要是指获取链接对象的策略。java

    6.一、基于XML的抓取sql

    1.一、基于XML抓取many-to-onesession

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.二、设置fetch="join"app

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"/>

    存在问题:延迟加载失效fetch

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

    1.三、可是fetch="join"没法抓取HQL中的list,若是须要抓取HQL中的list有两种方法:this

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

<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(*)查询)ssr

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.四、集合抓取code

<!-- 设置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。xml

    其中在查询单个对象时,select和subselect彻底同样,都是在须要查询集合对象时才发出sql,可是join会
    使用链接查询。

    在查询列表对象时,select和join同样(能够经过设置set的batch-size设置抓取的数量)

最佳实践:不少状况不会设置one-to-many,若是要设置one-to-many能够设置为subselect。

    6.二、基于Annotation的抓取

    一、基于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;

    二、集合抓取

@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() {
相关文章
相关标签/搜索