显式加载实体的集合

时间:2017-03-09 12:54:48

标签: java spring hibernate redis

我有这个实体User并且它有一个我想要redis缓存的角色集合(Set),所以每当它调用getRoles()时,它都会返回一个缓存副本。

到目前为止,这是结构:

  1. User.roles是lazy =“true”和access =“field”。
  2. User.getRoles()有一个调用spring @Cacheable方法的监听器 它从redis缓存而不是二级缓存中检索。
  3. 映射信息:

    <set
                name="roles"
                table="user_role"
                lazy="true"
                cascade="none"
                access="field"
            >
                <key
                    column="user_id"
                >
                </key>
                <many-to-many
                    class="com.resolution.scheduler.model.Role"
                    column="role_id"
                    outer-join="auto"
                 />
            </set>
    

    这是GetRoles():

    public Set getRoles() {
            if(!rolesUpdated  &&  this.id!=null){
                ApplicationContextProviderNonManageBean.getApplicationContext().publishEvent(
                     new com.resolution.scheduler.dao.event.UserRoleGetEvent(this));
            }
                     return roles;
        }
    

    以下是UserRoleGetEvent事件触发时调用的内容:

    @Cacheable(value="userRoleByUserId" , key="#userId", condition="#userId!=null")
        public PersistentSet getUserRoleByUserId(final Long userId){
            if(userId==null){
                return new PersistentSet();
            }
            log.info("USer Role Getting from Database for User Id : "+userId);
            //final List<Role> roles=(List<Role>)getHibernateTemplate().find("Select u.roles from User u  where u.id=?",userId);
            final PersistentSet[] set= new PersistentSet[1];
            getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Object>(){
                public Object doInHibernate(Session session) throws HibernateException{
                    List roles=session.createQuery("Select u.roles from User u  where u.id=:userId").setParameter("userId",userId).list();
                    set[0]= new PersistentSet((SessionImpl)session, new HashSet(roles));
                    return null;
            }
            });
            log.info(set);
    
            return set[0];
        }
    

    以下是UserRoleGetEvent的工作原理:

    public void onApplicationEvent(UserRoleGetEvent event) {
            PersistentSet roles = userManager.getUserRoleByUserId(event.getUser().getId());
            event.getUser().setRoles((roles)); //**THIS_SET_MAKES_IT_DIRTY**
    
        }
    

    问题: 当我执行user.getRole()时,因为它为user.roles设置了一个新的集合,它会使会话变脏。 在这个脏会话中,每当调用flush时,delete所有rolesinsert所有角色都会被重新调整。我正在寻找的是如何让hibernate认为我的新集合就像检索的会话(实际上并非如此)并且不认为它是脏的。

    有任何变通方法或建议吗?

1 个答案:

答案 0 :(得分:0)

Hibernate不喜欢它的集合被改变。可能有用的是:

event.getUser().getRoles().clear();
event.getUser().getRoles().addAll(roles);
然而,我对你想要做的事情感到有些困惑。 getRoles上的User会触发一个事件,然后更改角色?

作为旁注,我在这里通过内存工作,但你的代码可以重构为:

@Cacheable(value="userRoleByUserId" , key="#userId", condition="#userId!=null")
public List<Role> getUserRoleByUserId(final Long userId){
    if(userId==null){
        return Collections.emptyList();
    }
    log.info("USer Role Getting from Database for User Id : "+userId);

    @SuppressWarning("unchecked")
    List<Role> result = (List<Role>) getHibernateTemplate().executeWithNativeSession(new HibernateCallback<Object>(){
        public Object doInHibernate(Session session) throws HibernateException{
            return session.createQuery("Select u.roles from User u  where u.id=:userId").setParameter("userId",userId).list();
        }
    });
    log.info(set);

    return result;
}

public void onApplicationEvent(UserRoleGetEvent event) {
    List<Role> roles = userManager.getUserRoleByUserId(event.getUser().getId());
    event.getUser().getRoles().clear(); // yes, I know, getRoles will throw an event and send you in an infinite loop...  Fixing that just means having another method
    event.getUser().getRoles().addAll(roles);
}
相关问题