Hibernate可以批量db查询二级缓存中的集合未命中吗?

时间:2014-01-15 18:38:19

标签: java hibernate

对于Hibernate 3.5.4,假设我有一个像这样定义的hibernate实体:

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Team {

    @Id
    protected Long id;
    protected List<Player> players;

    @OneToMany(targetEntity = Player.class, fetch = FetchType.LAZY)
    @JoinColumn(name = "team_id")
    @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
    @NotFound(action= NotFoundAction.IGNORE)
    @org.hibernate.annotations.BatchSize(size = 50)

    public List<Player> getPlayers() {
        return this.players;
    }

    public List<Player> setPlayers(List<Player> players) {
        this.players = players;
    }

    // More stuff

}

然后我按照您的预期定义了一个Player实体。从逻辑上讲,这会创建三个二级对象缓存:

  • Team.players
  • 播放器

我发现,如果Team.players缓存被禁用或为查询的团队为空,Hibernate将向数据库发出批量请求,在那里它为一个团队检索所有玩家并进行一次查询(查找玩家。 team_id = Team.Id)。但是,如果Team.players缓存包含Team和播放器列表之间的缓存关联,并且Player缓存中没有这些Player对象,则Hibernate将一次检索每个Player对象由Player.Id提供单独的数据库查询。 有没有办法让Hibernate批量检索这些集合字段对象缓存未命中?

我已尝试为以下参数设置值,但它们似乎不会影响此行为:

  • default_batch_fetch_size
  • jdbc.batch_versioned_data
  • jdbc.batch_size
  • jdbc.fetch_size

我也尝试过EAGER取代而不是LAZY。

2008年的这个hibernate论坛帖子暗示了这个问题(https://forum.hibernate.org/viewtopic.php?t=983649),但我没有提出任何解决方案。谢谢你的帮助!

1 个答案:

答案 0 :(得分:0)

是的,你可以这样做。

构建Collection<Long>(假设这是您的玩家ID类型)。迭代团队的玩家列表,用Hibernate.isInitialized(player)检查玩家对象。如果为false,则将id添加到集合中。这假设你的@Id在玩家的id getter(不是字段)上,所以你可以从玩家代理获取id而无需转到DB。

如果您使用的是Java EE 6:而不是Hibernate.isInitialized(player),请尝试em.getEntityManagerFactory().getPersistenceUnitUtil().isLoaded(player)。这是容器独立性的首选。

当您获得列表时,检查它是否为空。如果它不为空,请运行查询:

SELECT p
JOIN Player p
WHERE p.id IN (:idList)

使用idList

设置Collection<Long>参数

只需运行query.getResultList();不要在任何地方存储查询结果。这将实现先前从团队集合加载的任何代理。