hibernate抓取策略

2019-03-03 13:51|来源: 领悟书生

按照学习hibernate高级特性之前准备的数据,执行以下查询

Student stu = (Student)session.load(Student.class, 1);
System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+
        stu.getClassroom().getSpecial().getName());

发现默认情况会发出3条SQL语句,一条取student,一条取Classroom,一条取Special

原因是:在many-to-one 里面有个fetch属性,它有两个值:select和join。默认是select。当改成join后看到 仅有的一个sql

通过设置XML中的many-to-one的fetch="join"完成对抓取的设置,这样就只发1天SQL语句

Student.hbm.xml

<many-to-one name="classroom" column="cid" fetch="join"/>

Classroom.hbm.xml

<many-to-one name="special" column="spe_id" fetch="join"/>


使用fetch=join虽然可以将关联对象抓取,但是如果不使用关联对象也会一并查询出来(这样会占用相应的内存)

Student stu = (Student)session.load(Student.class, 1);
//延迟加载就失效
System.out.println(stu.getName());


List<Student> stus = session.createQuery("from Student").list();
for(Student stu:stus) { 
    System.out.println(stu.getName()+","+stu.getClassroom());
}

在XML中配置了fetch=join仅仅只是对load的对象有用,对HQL中查询的对象无用,所以此时会发出查询班级的SQL,解决的这个SQL的问题有两种方案

1.一种是设置对象的抓取的batch-size,annotation使用@BatchSize(size=20)注解

<class name="Classroom" table="t_classroom" batch-size="20">

2.另一种方案在HQL中使用fecth来指定抓取(特别注意,如果使用了join fetch就无法使用count(*)

List<Student> stus = session.createQuery("select stu from " +
    "Student stu join fetch stu.classroom").list();
for(Student stu:stus) {
    System.out.println(stu.getName()+","+stu.getClassroom());
}


再来看看一个查询

Classroom cla = (Classroom)session.load(Classroom.class, 1);
//发一条取班级信息的SQL
System.out.println(cla.getName());
//此时会在发出一条SQL取学生对象
for(Student stu:cla.getStus()) {
    System.out.println(stu.getName());
}

如果想一条语句搞定,可以更改Classroom.hbm.xml中的的set里加fetch="join",在annotation中用@Fetch(FetchMode.JOIN)

<set name="stus" inverse="true" lazy="extra" fetch="join">


对于通过HQL取班级列表并且获取相应的学生列表时,fecth=join就无效了(发出很多语句)

List<Classroom> clas = session.createQuery("from Classroom").list();
for(Classroom cla:clas) {
    System.out.println(cla.getName());
    for(Student stu:cla.getStus()) {
        System.out.print(stu.getName());
    }
}

第一种方案可以设置set的batch-size来完成批量的抓取

第二中方案可以设置fetch=subselect,使用subselect会完成根据查询出来的班级进行一次对学生对象的子查询,在annotation中用@Fetch(FetchMode.SUBSELECT)

<set name="stus" inverse="true" lazy="extra" fetch="subselect">




对于Annotation的配置而言,默认就是基于join的抓取的,所以只会发出一条SQL

Student stu = (Student)session.load(Student.class, 1);
System.out.println(stu.getName()+","+stu.getClassroom().getName()+","+
    stu.getClassroom().getSpecial().getName());

由于基于Annotation的配置没有延迟加载,此时会把所有的关联对象查询上来,发大量的SQL语句

List<Student> stus = session.createQuery("from Student").list();
for(Student stu:stus) {
    System.out.println(stu.getName()+","+stu.getClassroom());
}

基于Annotation更改fetch的方法

//LAZY就是XML中的select,EAGER就表示XML中的join
@ManyToOne(fetch=FetchType.LAZY)


本文链接:hibernate抓取策略,领悟书生学习笔记,转载请注明出处http://www.656463.com/article/418

相关问答

更多
  • 网络爬虫是一个自动提取网页的程序,它为搜索引擎从万维网上下载网页,是搜索引擎的重要组成。传统爬虫从一个或若干初始网页的URL开始,获得初始网页上的URL,在抓取网页的过程中,不断从当前页面上抽取新的URL放入队列,直到满足系统的一定停止条件 爬虫的工作流程较为复杂,需要根据一定的网页分析算法过滤与主题无关的链接,保留有用的链接并将其放入等待抓取的URL队列。然后,它将根据一定的搜索策略从队列中选择下一步要抓取的网页URL,并重复上述过程,直到达到系统的某一条件时停止 (1) 对抓取目标的描述或定义;    ...
  • 您的映射看起来很好,所以我怀疑配置被引导过程中的某些东西覆盖了。 尝试在此代码块的EntityManagerFactoryBuilderImpl.processProperties()方法中添加断点: else if ( AvailableSettings.NAMING_STRATEGY.equals( keyString ) ) { namingStrategy = strategySelector.resolveStrategy( NamingStrategy.class, entry.getV ...
  • 吹,你应该在选择某种继承策略时保持性能问题 。 在这里您可以看到有关可用继承策略的良好洞察。 不要忘记,继承可以重新编写为一个关联,如下所示 代替 public class A {} public class B extends A {} 您可以使用 public class B { private A a; } 或者您可以使用MapedSuperClass使用任何Hibernate / JPA继承策略映射所有继承的属性。 看到这里 请记住,当使用默认的JPA / Hibernate注释时 ...
  • hibernate.ejb.naming_strategy用于JPA 。 您可以通过LocalSessionFactoryBuilder#setNamingStrategy()设置命名策略。 看起来,Hibernate 4中没有一个属性可以将Configuration策略设置为Configuration作为属性。 hibernate.ejb.naming_strategy is used for JPA. You can set a naming strategy by LocalSessionFactor ...
  • 我同意你的看法, EnumType.STRING更加强大,特别是在重构源代码时,因为enum中的常量的chaging顺序通常是通过疏忽来完成的(或者仅仅是因为有人按字母顺序对它们进行排序)。 但是你也没有办法改变默认行为,因为ORDINAL映射已经被设计为默认行为(可能是因为数字列比varchar类型列更有效)。 I agree with you that EnumType.STRING is more robust especially when refactoring source code as ch ...
  • 当我理解你正确的问题而不是你想知道hibernate在那种情况下是否会在你查询所有人时自动返回Employees。 此外,如果在将对象声明为Person p = new Employee()时插入Employee。 答案都是肯定的。 更详细。 插入操作基于对象的实际类型,而不是源代码中写入的类型。 与查询人员有关。 Hibernate确实将外连接保留为所有子类型,因此当您执行以下操作时,您还将获得Employess: Query query = session.createQuery("From Perso ...
  • 我不认为Hibernate会试图帮助你,因为这个领域的需求可能非常复杂和定制。 我在猜测,如果用户要保存一个已被另一个用户同时更改的对象,那么您很可能不想简单地加载该对象并复制所有更改的字段并撤消所有其他用户更改。 如果两个用户都改变了相同的字段会发生什么 您可能想向用户展示这两个版本,并要求他们决定哪个版本是正确的。 有点像合并版本控制系统中的更改。 如果你只是简单地合并后端同一个实体的两个版本并保存,那么你也可能有UI级别的验证链接可能违反的字段。 I don't think Hibernate wil ...
  • 我在Hibernate源代码中看不到一种方法。 EntityBinder使用ObjectNameNormalizer.NamingStrategyHelper提供名称,该名称从Configuration.namingStrategy (全局名称)获取命名策略,或者从通过MetadataImpl并且无处可用(无用途)的复杂路径获取命名策略。 所以你可能会用手工重写字段名称。 我甚至都没有看到明确的方式来获得关于该领域的背景知识,所以我认为即使是一个裂脑命名策略看起来也是不可能的。 更新 :在看到@ antho ...
  • 你有这个属性 jpaProperties.put("hibernate.dialect","org.hibernate.dialect.HSQDialect"); 这意味着项目应该在类路径中有一个org.hibernate.dialect.HSQDialect类。 你可以检查。 Hibernate核心jar中有HSQLDialect类。 You have this property jpaProperties.put("hibernate.dialect","org.hibernate.dialect.H ...
  • 发生异常是因为您在加载的hibernate会话关闭后尝试访问域对象上的延迟加载属性。 解决此问题的常用方法是使用Spring OpenSessonInViewFilter。 这基本上将你的hibernate会话范围扩展到你的HTTP请求。 然后,在该HTTP请求/响应周期内发生的任何属性访问都将在该会话的范围内。 你可以在你的web.xml中配置它,如下所示: Spring OpenSessionInViewFilter ...