hibernate之載入策略
1. 物件(hibernate管理的物件)的三種狀態:臨時狀態、持久狀態、遊離狀態
a、hibernate通過管理物件來操作資料庫,這裡物件指的是持久態的物件
b、各種狀態的物件是可以相互轉換
2、一級快取與快照
一級快取又被成為session級別的快取,相當於資料庫中的某條資料在hibernate產生一個快照,並且將值封裝進物件裡,如果說物件發生了改變,那麼它會與之前的hibernate中的快照進行對比,如果不一致,那麼就會修改資料庫中的資料,以下程式碼可體現:
package com.zking.three.test; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; import com.zking.one.entity.User; public class Demo1 { public static void main(String[] args) { Configuration cfg=new Configuration().configure(); SessionFactory sessionFactory=cfg.buildSessionFactory(); Session session = sessionFactory.openSession(); Transaction transaction = session.beginTransaction(); User user = session.get(User.class, 3);//根據ID將user查出來 user.setUserName("小明");//給user重新賦一個name transaction.commit();//提交事務 session.close();//關閉session } }
執行後資料庫裡的資料就會發生改變
3. 載入策略
a、立即載入,即session的get方法
b、延遲載入(懶載入),懶載入就是將查詢的oid(object id)儲存到session的代理proxy中,當真正要用到查詢的物件時,再去執行查詢的SQL語句,即session的load方法
package com.zking.three.test; import org.hibernate.Session; import org.hibernate.Transaction; import com.zking.one.entity.User; import com.zking.two.entity.Student; import com.zking.two.util.SessionFactoryUtil; public class UserDao { /** * 立即載入 * @author LJ * @Date 2018年10月22日 * @Time 下午3:02:01 * @param user * @return */ public User getUser(User user) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); User u = session.get(User.class, user.getId()); transaction.commit(); SessionFactoryUtil.closeSession(); return u; } /** * 懶載入(延時載入) * @author LJ * @Date 2018年10月22日 * @Time 下午2:57:14 * @param user * @return */ public User loadUser(User user) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); User u = session.load(User.class, user.getId()); transaction.commit(); SessionFactoryUtil.closeSession(); return u; } /** * 併發修改例子所用 * @author LJ * @Date 2018年10月23日 * @Time 下午1:44:58 * @param student */ public void updateStudent(Student student) { Session session = SessionFactoryUtil.getSession(); Transaction transaction = session.beginTransaction(); session.update(student); transaction.commit(); SessionFactoryUtil.closeSession(); } }
測試立即載入:
@Test
public void testGetUser() {
User user=new User();
user.setId(3);
User u = new UserDao().getUser(user);
System.out.println(u.getUserName());
}
效果:
測試懶載入:
@Test public void testLoadUser() { User user=new User(); user.setId(3); User u = new UserDao().loadUser(user); System.out.println(u.getUserName()); }
效果:
報LazyInitializationException異常,是因為懶載入是當真正要用到查詢的物件時,再去執行查詢的SQL語句,但這時session已經關閉了,所以會出現異常
4、併發控制
業務場景:不同的兩個使用者同時對同一條資料進行修改,後提交的資訊會覆蓋先提交的資訊,針對這一現象,hibernate提供瞭解決方法,就是在資料庫裡和實體類里加一個version列段(資料庫裡該列段須為int型別,預設值為1),再在xml裡進行配置
注:配置時version屬性要放在property屬性的前面
測試:
@Test
public void testUpdateStudent() {
Student student=new Student();
student.setSid(5);
student.setVersion(2);
student.setSname("劉備");
new UserDao().updateStudent(student);
}
每一次修改成功後,資料庫裡version會自增1,若修改時version的值沒有與資料庫裡的對應則會報錯:ERROR: HHH000346: Error during managed flush [Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.zking.two.entity.Student#5]]