Hibernate session get()和load()区别,及疑问

Hibernate  session.load() 和session.get() 都能获取对象,并且获取的对象是持久态。

但是二者有区别:

1、当使用load方法来得到一个对象时,此时hibernate会使用延迟加载的机制来加载这个对象。即:当我们使用session.load()方法来加载一个对象时,此时并不会发出sql语句,当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,只有当我们要使用这个对象,得到其它属性时,这个时候才会发出sql语句,从数据库中去查询我们的对象

2、当使用Session的get()方法时,如果加载的数据不存在,get()方法会返回一个NULL;但是使用load()方法,若加载的数据不存在,则会抛出异常。对于load方法,虽然加载的数据不存在,但是如果不使用加载出来的这个entity的属性,也不会出现异常。

针对第二点的例子:

Session session=    createSession();

TestUser userGet=session.get(TestUser.class, 9);

TestUser userLoad=  session.load(TestUser.class, 10);

if(userLoad==null) {

System.err.println("load: null");

}

//System.err.println("load:"+userLoad.toString());

session.close();

session中 Id为9 和10 的实体都没有,并且数据库中也没有

控制台打印出来的日志:

只有关于get   id为9 的实体的sql,并没有关于id 为10的sql。这里id为9和10的实体,在数据库中并没有数据,但是Load方法却没有报错,正是因为没有使用到load获得的实体的属性,虽然使用了userLoad==null的判断。

当打开userLoad.toString()注释时,

Session session=    createSession();

TestUser userGet=session.get(TestUser.class, 9);

TestUser userLoad=  session.load(TestUser.class, 10);

if(userLoad==null) {

System.err.println("load: null");

}

System.err.println("load:"+userLoad.toString());

session.close();

看看控制台日志:

23:13:45.978 [main] DEBUG org.hibernate.SQL -

    select

        testuser0_.id as id1_0_0_,

        testuser0_.PASSWORD as PASSWORD2_0_0_,

        testuser0_.USER_NAME as USER_NAM3_0_0_

    from

        user testuser0_

    where

        testuser0_.id=?

Hibernate:

    select

        testuser0_.id as id1_0_0_,

        testuser0_.PASSWORD as PASSWORD2_0_0_,

        testuser0_.USER_NAME as USER_NAM3_0_0_

    from

        user testuser0_

    where

        testuser0_.id=?

23:13:45.998 [main] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered

23:13:45.999 [main] DEBUG org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader - Done entity load : com.hjb.Sboot.TestUser#9

23:13:45.999 [main] DEBUG org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl - Initiating JDBC connection release from afterTransaction

23:13:49.745 [main] DEBUG org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl - Initiating JDBC connection release from afterTransaction

23:13:49.748 [main] DEBUG org.hibernate.internal.SessionImpl - Initializing proxy: [com.hjb.Sboot.TestUser#10]

23:13:49.750 [main] DEBUG org.hibernate.SQL -

    select

        testuser0_.id as id1_0_0_,

        testuser0_.PASSWORD as PASSWORD2_0_0_,

        testuser0_.USER_NAME as USER_NAM3_0_0_

    from

        user testuser0_

    where

        testuser0_.id=?

Hibernate:

    select

        testuser0_.id as id1_0_0_,

        testuser0_.PASSWORD as PASSWORD2_0_0_,

        testuser0_.USER_NAME as USER_NAM3_0_0_

    from

        user testuser0_

    where

        testuser0_.id=?

23:13:49.752 [main] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered

23:13:49.752 [main] DEBUG org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader - Done entity load : com.hjb.Sboot.TestUser#10



Exception in thread "main" org.hibernate.ObjectNotFoundException: No row with the given identifier exists: [com.hjb.Sboot.TestUser#10]

       at org.hibernate.boot.internal.StandardEntityNotFoundDelegate.handleEntityNotFound(StandardEntityNotFoundDelegate.java:28)

       at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:244)

       at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:166)

       at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:268)

       at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)

       at com.hjb.Sboot.TestUser_$$_jvste85_0.toString(TestUser_$$_jvste85_0.java)

       at com.hjb.Sboot.SbootApplication.getAndLoad(SbootApplication.java:67)

       at com.hjb.Sboot.SbootApplication.main(SbootApplication.java:57)

从控制台可以看出:

当使用到load出来的实体的属性时,就会执行sql,并且load的实体不存在时,并且报错。

 

针对第一点的例子:

Session session=    createSession();

TestUser userGet=session.get(TestUser.class, 7);

TestUser userLoad=  session.load(TestUser.class, 6);

System.err.println("load:"+userLoad.getId());

session.close();

load方法执行后,显示load出来的实体的id,

13:33:55.651 [main] DEBUG org.hibernate.engine.transaction.internal.TransactionImpl - begin

13:33:55.662 [main] DEBUG org.hibernate.SQL -

    select

        testuser0_.id as id1_0_0_,

        testuser0_.PASSWORD as PASSWORD2_0_0_,

        testuser0_.USER_NAME as USER_NAM3_0_0_

    from

        user testuser0_

    where

        testuser0_.id=?

Hibernate:

    select

        testuser0_.id as id1_0_0_,

        testuser0_.PASSWORD as PASSWORD2_0_0_,

        testuser0_.USER_NAME as USER_NAM3_0_0_

    from

        user testuser0_

    where

        testuser0_.id=?

13:33:55.677 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl - Starting ResultSet row #0

13:33:55.677 [main] DEBUG org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl - On call to EntityIdentifierReaderImpl#resolve, EntityKey was already known; should only happen on root returns with an optional identifier specified

13:33:55.685 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Resolving associations for [com.hjb.Sboot.TestUser#7]

13:33:55.686 [main] DEBUG org.hibernate.engine.internal.TwoPhaseLoad - Done materializing entity [com.hjb.Sboot.TestUser#7]

13:33:55.687 [main] DEBUG org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl - HHH000387: ResultSet's statement was not registered

13:33:55.687 [main] DEBUG org.hibernate.loader.entity.plan.AbstractLoadPlanBasedEntityLoader - Done entity load : com.hjb.Sboot.TestUser#7

load:6

控制台日志看出,只调用load的实体的id,并不会执行sql,正好映证第一点中load

当前得到的这个对象其实是一个代理对象,这个代理对象只保存了实体对象的id值,只有当使用这个对象,得到其它属性时,这个时候才会发出sql语句,从数据库中去查询对象.

注意一点:最开始在映证这一点的时候,是在debug模式下去查看的load的实体的值。本以为得到的实体的属性只有id有值,其他属性都没有值。结果与理论似乎是矛盾的,真的是这样的吗?先看debug模式下的控制台日志:T

estUser userGet=session.get(TestUser.class, 7);

TestUser userLoad=  session.load(TestUser.class, 6);

//System.err.println("load:"+userLoad.getId());

//System.err.println("load:"+userLoad.toString());

session.clear();

session.close();

这是get方法得到的对象的值,是正常的

到执行load方法后,查看load方法得到的对象的值,理论是应该只有id有值,看图说话。

是不是很矛盾?

但是

如果细心的人会发现:

debug模式下,当执行了load方法后,控制台并没有出现关于id6时的任何日志,而当鼠标放到Load方法得到的对象的变量上时,即本例code中的userLoad变量上时,关于id6的日志立马出现sql

 

见图:

当执行了load方法后,控制台并没有出现关于id6 的任何日志及sql

 

当把鼠标放到userLoad对象上去查看对象的属性值时,控制台立马出现日志

 

原来debug模式下,去查看对象的值时,会调用对象的toString方法。

关于IDEA debug模式下默认调用对象的toString方法:

https://blog.csdn.net/dajiangqingzhou/article/details/78676459

 

猜你喜欢

转载自blog.csdn.net/qq_26817225/article/details/81387403