如何在Hibernate中使用READ_WRITE CacheConcurrencyStrategy保持缓存的ManyToOne集合的一致性?

时间:2012-09-07 18:41:57

标签: java hibernate

在编写“非规范化”集合时,我遇到了NONSTRICT_READ_WRITE和READ_WRITE CacheConcurrencyStrategy之间的区别......我的想法是我将一个连接表建模为一个实体,但它还包含指向它连接到的表的只读链接。

我的实体,粗略地说:

@Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
class Actor {
    @Id
    Integer id;
    @Column
    String name;
}

@Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
class Movie {
    @Id
    Integer id;
    @Column
    String title;
}

@Entity
@org.hibernate.annotations.Entity(dynamicUpdate = true)
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
class Credit {
    @Column
    String roleName;

    @ManyToOne(targetEntity = Movie.class, optional = true)
    @JoinColumn(name = "movie_id", insertable = false, updatable = false)
    @NotFound(action = NotFoundAction.IGNORE)
    Movie movie;

    @Column(name = "movie_id")
    Long movieId;

    @ManyToOne(targetEntity = Actor.class, optional = true)
    @JoinColumn(name = "actor_id", insertable = false, updatable = false)
    @NotFound(action = NotFoundAction.IGNORE)
    Actor actor;

    @Column(name = "actor_id")
    Long actorId;
}

启用第二级对象缓存(使用ehcache)。

我的应用程序会编写电影和演员......稍后,它会通过编写信用点将它们链接在一起。写入Credit时,我只填写roleName,movieId和actorId字段,我不提供Movie和Actor对象。

使用NONSTRICT_READ_WRITE缓存,我可以读回该Credit对象,它将包含引用的Movie和Actor对象。

使用READ_WRITE缓存,回读Credit将返回带有空Movie和Actor字段的Credit。如果我清除了hibernate缓存,那么回读那个Credit然后按预期包含Movie和Actor对象。这也是TRANSACTIONAL缓存的行为(但当然不是使用NONE缓存)。

因此,当使用READ_WRITE缓存时,hibernate似乎将Credit插入到具有空Actor和Movie字段的二级缓存中。有没有办法防止这种情况发生,并始终从数据库中读取以获取这些连接的字段?我尝试使用CacheConcurrencyStrategy.NONE注释字段,但这不起作用。

1 个答案:

答案 0 :(得分:0)

我认为你可能偶然发现了一个hibernate bug,因为你的怪异映射(至少是非标准映射)。没有真正的理由让两个字段一个带有id,一个带有实体。

您可以使用session.load将ID转换为实体引用 - 这只是创建代理,不会从数据库加载数据。

如果你摆脱movieId和actorId字段并删除movie / actor字段中的insertable / updatable false,它应该与READ_WRITENON_STRICT_READ_WRITE

无关。
Credit c = new Credit()
Movie m = session.load(movieId);
Actor a = session.load(actorId);
c.setMovie(m);
c.setActor(a);
session.save(c);

Hibernate不会将完整对象保存在二级缓存中。我将它存储为扁平形式(水合 - 更像db表)并从中重建对象。所以你断言它将对象存储在缓存中并且没有更新它是不正确的。还有其他事情要发生。

READ_WRITENON_STRICT_READ_WRITE之间的主要区别在于,在READ_WRITE的情况下,缓存中的条目将在更新时被锁定,并且不会在NON_STRICT_READ_WRITE中被锁定。这只会影响您同时在多个线程中更新此实体。