从Hibernate源码看@NotFound(action=NotFoundAction.IGNORE) 会导致Eager加载 @ManyToOne(fetch = FetchType.LAZY)无效

  记得刚进项目组的时候leader给我介绍过NotFound(action=NotFoundAction.IGNORE)会导致Fetch无效,这样的话无论你设置fetchType是lazy还是eager都会以eager加载,一开始我开始模糊的记住,但是过不了2天就会忘,今天有个任务也是配Ignore的,索性就看看里面到底是怎么整的,下面把发现的贴出来:

  先看org.hibernate.type.ManyToOneType

public class ManyToOneType extends EntityType {
    
    private final boolean ignoreNotFound;

    public ManyToOneType(String className) {
        this( className, false );
    }

    public ManyToOneType(String className, boolean lazy) {
        super( className, null, !lazy, true, false );
        this.ignoreNotFound = false;
    }

      这里可以清楚的看到对ManyToOneType来说 默认的是eager加载(前两个红色标注),ignoreNotFound是false,也就是说默认的NotFound不是ignore,即是Exception

好的,接着往下看org.hibernate.impl.SessionImpl的internalLoad方法:  

 public Object internalLoad(String entityName, Serializable id, boolean eager, boolean nullable) throws HibernateException {
        // todo : remove
        LoadEventListener.LoadType type = nullable ?
                LoadEventListener.INTERNAL_LOAD_NULLABLE :
                eager ? LoadEventListener.INTERNAL_LOAD_EAGER : LoadEventListener.INTERNAL_LOAD_LAZY;
        LoadEvent event = new LoadEvent(id, entityName, true, this);
        fireLoad(event, type);
        if ( !nullable ) {
            UnresolvableObjectException.throwIfNull( event.getResult(), id, entityName );
        }
        return event.getResult();
    }

这里假设你ManyToOne上设置的是NotFoundAction.IGNORE,ignoreNotFound这个属性就会设置为true,掉这个方法时传进来的boolean nullable就是true,这是大前提。

看红色字体的三目运算符,a?b:c,计算规则,先计算a,a为true的话计算b的值返回,a为false计算c的值返回。对a?b:c?d:e这个有点复杂,可以这样换算a?b(c?d:e).也就是说a为false的话计算c?d:e的值返回。

由于nullable是true,咱们就看INTERNAL_LOAD_NULLABLE 这几个常量的值。

下面看org.hibernate.event.LoadEventListener:   

public static final LoadType INTERNAL_LOAD_EAGER = new LoadType("INTERNAL_LOAD_EAGER")
            .setAllowNulls(false)
            .setAllowProxyCreation(false)
            .setCheckDeleted(false)
            .setNakedEntityReturned(false);
    
    public static final LoadType INTERNAL_LOAD_LAZY = new LoadType("INTERNAL_LOAD_LAZY")
            .setAllowNulls(false)
            .setAllowProxyCreation(true)
            .setCheckDeleted(false)
            .setNakedEntityReturned(false);
    
    public static final LoadType INTERNAL_LOAD_NULLABLE = new LoadType("INTERNAL_LOAD_NULLABLE")
            .setAllowNulls(true)
            .setAllowProxyCreation(false)
            .setCheckDeleted(false)
            .setNakedEntityReturned(false);

这里看到 .setAllowProxyCreation(false) 也就是代理创建false,这样话就不是懒加载!!!看到设置为lazy的是.setAllowProxyCreation(true),设置为eager的是.setAllowProxyCreation(false),基本能说明eager不创建代理,lazy是代理加载

最后再贴段代码证明哪里调用这布尔值:

org.hibernate.event.def.DefaultLoadEventListener 

的proxyOrLoad方法:

if ( options.isAllowProxyCreation() ) {
                    return createProxyIfNecessary( event, persister, keyToLoad, options, persistenceContext );
                }
                else {
                    // return a newly loaded object
                    return load(event, persister, keyToLoad, options);
                }
            }

看hibernate上的注解写的很清楚,如果AllowProxyCreation这布尔值为false的话会返回一个新的加载对象!


从上面的代码不难从hibernate框架的代码中看出hibernate的一些默认设置方式。这里还多亏maven的应用,要是以前不用maven,想一窥ssh的源码还要自己下载,自己加载进去,效率低而繁琐,万一换个workspase就得重新来一遍。

一天进步一点点。




你可能感兴趣的:(j2ee)