对于 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 缓存被禁用或为空,Hibernate 会向数据库发出批量请求,在该数据库中通过一个查询检索团队的所有玩家(查找player.player.player)。 team_id = 团队 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 ),但我还没有找到任何解决方案。感谢您的帮助!
最佳答案
是的,你可以做到。
建立一个Collection<Long>
(假设这是您的玩家 ID 类型)。迭代球队的球员列表,使用 Hibernate.isInitialized(player)
检查球员对象。如果为 false,则将 id 添加到集合中。这是假设你的 @Id
位于玩家的 id getter 上(而不是字段),因此您可以从玩家代理获取 id,而无需访问数据库。
如果您使用的是 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()
;不必费心将查询结果存储在任何地方。这将具体化之前从团队集合中加载的所有代理。
关于java - Hibernate可以批量数据库查询二级缓存中集合未命中的情况吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21145605/