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方法後,控制檯並沒有出現關於id爲6時的任何日誌,而當鼠標放到Load方法得到的對象的變量上時,即本例code中的userLoad變量上時,關於id爲6的日誌立馬出現sql。
見圖:
當執行了load方法後,控制檯並沒有出現關於id爲6 的任何日誌及sql
當把鼠標放到userLoad對象上去查看對象的屬性值時,控制檯立馬出現日誌
原來debug模式下,去查看對象的值時,會調用對象的toString方法。
關於IDEA debug模式下默認調用對象的toString方法:
https://blog.csdn.net/dajiangqingzhou/article/details/78676459