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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章