在使用load()方法加載持久化對象是,它返回的是一個未初始化的代理(即未從數據庫中抓取數據對象的數據),直到調用代理的某個方法時Hibernate纔會訪問數據庫。而非延遲加載過程中,Hibernate會直接訪問數據庫,並不會使用代理對象。
而恰恰是因爲這種情況,測試load方法會有一些不同的問題出現
@Test
public void testload01() {
Session session = null;
try {
session = HibernateUtil.openSession();
session.beginTransaction();
User user = (User)session.load(User.class, 33);
System.out.println(user.getId());
} catch (Exception e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession(session);
}
}
id爲33的數據在數據庫中並不存在,但以此方法卻能輸出33.
而將輸出語句換爲
System.out.println(user.getNickname());
則會拋出org.hibernate.ObjectNotFoundException異常: No row with the given identifier exists: [com.norman.model.User#33]
這是因爲輸出id時id是從代理中讀取的,而而輸出Nickname時則需要從數據庫中抓取數據,數據庫中並沒有這個對象,但是user並不是空。
使用get()方法則是直接從數據庫中抓取數據,因爲不存這個對象,所以拋出的是空指針異常。
當使用userDao的方式加載數據時,同樣會出現一些不同於mybatis框架下load()方法的問題:
//UserDao文件中load方法
public User load(int id){
Session session = null;
User user = new User();
try {
session = HibernateUtil.openSession();
session.beginTransaction();
user = (User)session.load(User.class, id);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
}finally{
HibernateUtil.closeSession(session);
}
return user;
}
單元測試文件方法
@Test
public void testLoad() {
UserDao userDao = new UserDao();
User user = userDao.load(3);
System.out.println(user);
}
這種方法並不能輸出user對象,而是出現異常:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:165)
at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:286)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at com.norman.model.User_$$_jvst1b4_0.toString(User_$$_jvst1b4_0.java)
at java.lang.String.valueOf(Unknown Source)
at java.io.PrintStream.println(Unknown Source)
at com.norman.test.TestLazy.testLoad(TestLazy.java:16)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
這是因爲使用load方法延遲加載,返回時只是一個代理對象僅僅只有一個id。在真正調用的時候Session已經關閉,此時需要從數據庫中讀取數據時Session已經關閉所以會拋出上述異常。使用get方法以非延遲加載的方式解決的辦法之一