首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么OnPostUpdate中的Session.Evict会导致“可能的会话非线程安全访问”异常?

为什么OnPostUpdate中的Session.Evict会导致“可能的会话非线程安全访问”异常?
EN

Stack Overflow用户
提问于 2012-10-04 19:37:08
回答 3查看 16.9K关注 0票数 8

我有一个拥有多个角色的用户。使用链接实体表将用户链接到角色。我已经将配置文件设置为在删除用户时级联删除用户角色链接实体。

我们目前正在使用软删除来删除实体。我们添加了一个软删除事件监听器,该监听器由delete触发。当实体被删除时,它会触发DeleteEntity事件,该事件将实体标记为已删除。

我们还有一个重写OnPostUpdate事件,通过在实体上调用Evict来从缓存中删除实体。

如果我创建了一个没有任何角色的用户,然后删除它,一切都可以正常工作(如果级联被禁用,它也可以工作)。然而,如果我有一个分配了至少一个角色的用户,并且我删除了这个用户,在OnPostUpdate中调用Evict之后,我得到了一个NHibernate异常"NHibernate.AssertionFailure:对会话的可能的非线程安全访问“。

OnPostUpdate中,我尝试使用子会话来驱逐实体,没有抛出异常,但是实体没有被驱逐。

代码语言:javascript
复制
public void UserDelete(.....)
{
    var user = repository.Fetch<User>(id);

    repository.Remove(user);
    repository.Connection.Commit();
}


// soft delete event listener
protected override void DeleteEntity(NHibernate.Event.IEventSource session, object entity, ..)
{               
    var repositoryEntity = entity as deletableentity;
    if (repositoryEntity != null)
    {
        if (!repositoryEntity.IsDeleted)
        {
            // this marks the entity as deleted
            repositoryEntity.isDeleted = true;

            // cascade delete
            this.CascadeBeforeDelete(session, persister, repositoryEntity, entityEntry, transientEntities);
            this.CascadeAfterDelete(session, persister, repositoryEntity, transientEntities);          
        }
    }
}

public void OnPostUpdate(PostUpdateEvent @event)
{
    if (@event == null) throw new ArgumentNullException("event");

    var entity = @event.Entity as deletableentity;

    // Evict any entities that have been set as deleted from first level cache.
    if (entity != null && entity.IsDeleted)
    {
        @event.Session.Evict(entity);
    }
}

有什么办法解决这个问题吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-10-05 17:47:39

找到问题所在。使用软删除实际上会触发update来设置isDeleted标志。由于映射中的这一行

代码语言:javascript
复制
  cascade="all"

级联适用于更新和逐出操作。我的postUpdate将被触发2次,但同时驱逐将尝试驱逐到子实体上。

解决方案是在映射文件中删除级联中的Evict。现在是:

代码语言:javascript
复制
  cascade="persist, merge, save-update, delete, lock, refresh"
票数 3
EN

Stack Overflow用户

发布于 2013-01-15 08:55:35

根据https://forum.hibernate.org/viewtopic.php?p=2424890的说法,避免这种情况的另一种方法是基本上调用

代码语言:javascript
复制
          session.save(s);
          session.flush(); // allow evict to work
          session.evict(s);

问题的根源在于“如果我从缓存中清除了实体,commit()就不会在那里找到它”(也就是说,这根本不是线程安全问题,而是缓存被修改的问题)。

票数 14
EN

Stack Overflow用户

发布于 2012-12-18 07:32:56

我遇到了同样的问题,但由于我使用的是流畅的映射,因此没有从级联中排除Evict的选项。我的解决方案是避免调用Evict,直接从会话缓存中删除实体:

代码语言:javascript
复制
public void OnPostUpdate(PostUpdateEvent @event)
{
    var entity = @event.Entity as ISoftDeletable;
    if (entity != null && entity.Deleted)
    {
        IEventSource session = @event.Session;
        IEntityPersister persister = @event.Persister;

        var key = new EntityKey(@event.Id, persister, session.EntityMode);
        session.PersistenceContext.RemoveEntity(key);
        session.PersistenceContext.RemoveProxy(key);
    }
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12726413

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档