对于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将向数据库发出批量请求,在那里它为一个团队检索所有玩家并进行一次查询(查找玩家。 team_id = Team.Id)。但是,如果Team.players缓存包含Team和播放器列表之间的缓存关联,并且Player缓存中没有这些Player对象,则Hibernate将一次检索每个Player对象由Player.Id提供单独的数据库查询。 有没有办法让Hibernate批量检索这些集合字段对象缓存未命中?
我已尝试为以下参数设置值,但它们似乎不会影响此行为:
我也尝试过EAGER取代而不是LAZY。
2008年的这个hibernate论坛帖子暗示了这个问题(https://forum.hibernate.org/viewtopic.php?t=983649),但我没有提出任何解决方案。谢谢你的帮助!
答案 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()
;不要在任何地方存储查询结果。这将实现先前从团队集合加载的任何代理。