代码之家  ›  专栏  ›  技术社区  ›  maaartinus

如何使用旧的hibernate标准获得批处理?

  •  0
  • maaartinus  · 技术社区  · 6 年前

    我还在用旧的 org.hibernate.Criteria 对获取模式越来越困惑。在各种查询中,我需要 以下所有变体 @ManyToOne(fetch=FetchType.LAZY) ,否则,不会更改查询中的任何内容。

    到目前为止,我所能找到的要么与HQL或JPA2有关,要么只提供了两种选择,但对于旧的标准和(至少)以下三种情况,我需要它:

    • 执行一个JOIN,然后从两个表中提取。这是正常的,除非数据太冗余(例如,主数据很大或在结果中重复多次)。在SQL中,我会写
      SELECT * FROM item JOIN order on item.order_id = order.id
      WHERE ...;
    • 做一个连接,从第一个表中提取,并从另一个表中分离。这通常是前一个查询的更有效的变体。在SQL中,我会写
      SELECT item.* FROM item JOIN order on item.order_id = order.id
      哪里。。。;

      SELECT order.* FROM order WHERE ...;

    • 选择item.*FROM item JOIN order on item.order\u id=order.id
      WHERE ...
      ORDER BY order.name, item.name;

    fetch=FetchType.LAZY ,所有的东西都像第一种情况一样被急切地抓取,这有时太糟糕了。我想,使用 Criteria#setFetchMode ,我可以拿到第三箱。我还没试过,因为我还没找到第二个案子。我知道这是 以某种方式 @BatchSize 注释。

    • 我说的对吗?
    • 有没有办法用旧的标准得到第二个病例?

    看起来像是用 createAlias() 导致急切地获取一切。有一些重载允许指定 JoinType ,但我需要指定获取类型。现在,我更困惑了。

    0 回复  |  直到 6 年前
        1
  •  1
  •   Thomas Portwood    6 年前

    projections (注:我刚刚用 Restrictions.like("name", "%s%") 为了确保检索到许多行):

    1. 执行一个JOIN,然后从两个表中提取。

      因为项目的顺序是FetchType.LAZY, the default fetch mode will be 'SELECT' 因此,只需将其设置为“JOIN”即可从JOIN而不是单独的查询中获取相关实体数据:

      Session session = entityManager.unwrap(org.hibernate.Session.class);
      Criteria cr = session.createCriteria(Item.class);
      cr.add(Restrictions.like("name", "%s%"));
      cr.setFetchMode("order", FetchMode.JOIN);
      List results = cr.list();
      results.forEach(r -> System.out.println(((Item)r).getOrder().getName()));
      

      生成的单个SQL查询:

      select
          this_.id as id1_0_1_,
          this_.name as name2_0_1_,
          this_.order_id as order_id3_0_1_,
          order2_.id as id1_1_0_,
          order2_.name as name2_1_0_ 
      from
          item_table this_ 
      left outer join
          order_table order2_ 
              on this_.order_id=order2_.id 
      where
          this_.name like ?
      
    2. 做一个JOIN,从第一个表中获取数据,并将数据从另一个表中分离出来。

      将fetch模式保留为默认的“SELECT”,为订单创建别名以在排序中使用其列,并使用 projection

      Session session = entityManager.unwrap(org.hibernate.Session.class);
      Criteria cr = session.createCriteria(Item.class);
      cr.add(Restrictions.like("name", "%s%"));
      cr.createAlias("order", "o");
      cr.addOrder(org.hibernate.criterion.Order.asc("o.id"));
      cr.setProjection(Projections.projectionList()
              .add(Projections.property("id"), "id")
              .add(Projections.property("name"), "name")
              .add(Projections.property("order"), "order"))
              .setResultTransformer(org.hibernate.transform.Transformers.aliasToBean(Item.class));
      List results = cr.list();
      results.forEach(r -> System.out.println(((Item)r).getOrder().getName()));
      
      

      生成的第一个SQL查询:

      select
          this_.id as y0_,
          this_.name as y1_,
          this_.order_id as y2_ 
      from
          item_table this_ 
      inner join
          order_table o1_ 
              on this_.order_id=o1_.id 
      where
          this_.name like ? 
      order by
          o1_.id asc
      

      @BatchSize(value=5) 在Order类上):

      select
          order0_.id as id1_1_0_,
          order0_.name as name2_1_0_ 
      from
          order_table order0_ 
      where
          order0_.id in (
              ?, ?, ?, ?, ?
          )
      
    3. 执行联接,但不获取联接表。

      与前一种情况相同,但是不要做任何事情来提示加载延迟加载的订单:

      Session session = entityManager.unwrap(org.hibernate.Session.class);
      Criteria cr = session.createCriteria(Item.class);
      cr.add(Restrictions.like("name", "%s%"));
      cr.createAlias("order", "o");
      cr.addOrder(Order.asc("o.id"));
      cr.setProjection(Projections.projectionList()
              .add(Projections.property("id"), "id")
              .add(Projections.property("name"), "name")
              .add(Projections.property("order"), "order"))
              .setResultTransformer(org.hibernate.transform.Transformers.aliasToBean(Item.class));
      List results = cr.list();
      results.forEach(r -> System.out.println(((Item)r).getName()));
      

      生成的单个SQL查询:

      选择
      此订单id为y2_
      从
      此表中的项目_
      内部连接
      订单表o1_
      在这个订单上\u id=o1 \u id
      哪里
      订货人
      o1\标识asc
      

    @Entity
    @Table(name = "item_table")
    public class Item {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        @ManyToOne(fetch = FetchType.LAZY)
        private Order order;
    
        // getters and setters omitted
    }
    
    @Entity
    @Table(name = "order_table")
    @BatchSize(size = 5)
    public class Order {
    
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
    
        private String name;
    
        // getters and setters omitted
    }