Hibernate二级缓存ObjectNotFoundException,具有大量并发事务

时间:2010-06-24 19:19:00

标签: java hibernate concurrency ehcache second-level-cache

我们有一个Java应用程序,它使用MySQL,Hibernate(3.5.1-Final)和EHcache(1.2.3)作为我们的二级缓存。

我们的hibernate.properties隔离级别是Read-committed isolation = 2

# 2-Read committed isolation 
hibernate.connection.isolation=2

在大量并发事务中,我们遇到一个问题,即加载时某些集合(数据库关联)​​将抛出ObjectNotFoundException,并且看起来第二级缓存正在返回该集合的旧副本。

我们有许多不同类型的交易可以访问此集合(仅限阅读),只有一对会添加/删除项目。

我们在单个事务负载或甚至中等事务负载(10 - 20个并发连接)下都没有看到此问题。

例如,我们有一个Character实体:

@Entity
@Table(name = "CHARACTERS")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Character extends AbstractCharacter implements Serializable {
...
    @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
    @OneToMany(mappedBy = "character", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private Set<CharacterItem> items;

我们在删除实体时正确维护对象图,方法是将它们从包含它们的集合中删除并调用session.delete()。

    character.getItems().remove(characterItem);
    session.delete(characterItem); 

我们尝试过更改Set项目; CacheConcurrencyStrategy来自:

@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
private Set<CharacterItem> items;

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private Set<CharacterItem> items;

没有运气。

我们不使用数据库锁,而是使用optimistic concurrency control来捕获并重试冲突的事务。

此时我们能看到的唯一两个解决方案是:

  1. 尝试捕获 ObjectNotFoundException 并尝试智能地逐出集合(尽管异常中似乎没有足够的上下文)

  2. 在items集合上使用 @NotFound(action=NotFoundAction.IGNORE) 注释,它将忽略而不抛出ObjectNotFoundException(但我们担心如何使用第二级缓存和确保它正在查看正确的数据)。

  3. 我希望有一个@NotFound(action = NotFoundAction.EVICT_2ND_LEVEL_CACHE_RELOAD),它会从缓存中驱逐该对象并尝试重新加载该集合。

    我们也可以尝试将FetchyType从LAZY更改为EAGER,但我想尝试了解问题并选择最佳解决方案,以便在高并发性下提供事务中的数据。

1 个答案:

答案 0 :(得分:1)

也许您应该尝试使用session.evict(characterItem)代替session.delete