hibernate(3)(对象的状态,一级缓存,懒加载)
对象的状态:
临时:new出 ;对象不在session管理,与数据库无对应的记录
持久:对象在session管理, 与数据库有对应的记录
有oid
对对象修改会同步到数据库
游离:对象不在session管理,但与数据库有对应的记录.
修改对象,不会影响数据库
当调用session的save/saveOrUpdate/get/load/list等方法的时候,对象就是持久化状态。
处于持久化状态的对象,当对对象属性进行更改的时候,会反映到数据库中!

Hibernate中缓存分类:
一级缓存
二级缓存
一级缓存:
目的:减少对数据库的访问次数!从而提升hibernate的执行效率!
1)Hibenate中一级缓存,也叫做session的缓存,它可以在session范围内减少数据库的访问次数! 只在session范围有效! Session关闭,一级缓存失效! 2)当调用session的save/saveOrUpdate/get/load/list/iterator方法的时候,都会把对象放入session的缓存中。 3)Session的缓存由hibernate维护,如果想操作缓存内容,必须通过hibernate提供的evit/clear方法操作。
特点:
只在(当前)session范围有效,作用时间短,效果不是特别明显!
在短时间内多次操作数据库,效果比较明显!

缓存相关几个方法的作用:
session.flush(); 让一级缓存与数据库同步
session.evict(arg0); 清空一级缓存中指定的对象
session.clear(); 清空一级缓存中缓存的所有对象
用于批量操作,比如:大量数据更新,不想缓存这些对象,可以先flush再clear。
public class Test{ private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(User.class) // 测试时候使用 .buildSessionFactory(); } @Test public void testCache() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; // 查询 user = (User) session.get(User.class, 5);// 先检查缓存中是否有数据,如果有不查询数据库,直接从缓存中获取 user = (User) session.get(User.class, 5);// 先检查缓存中是否有数据,如果有不查询数据库,直接从缓存中获取 session.getTransaction().commit(); session.close(); } @Test public void flush() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; user = (User) session.get(User.class, 5); user.setUserName("Jack"); // 缓存数据与数据库同步 session.flush(); user.setUserName("Jack_new"); session.getTransaction().commit(); // session.flush(); session.close(); } @Test public void clear() throws Exception { Session session = sf.openSession(); session.beginTransaction(); User user = null; // 查询 user = (User) session.get(User.class, 5); // 清空缓存内容 // session.clear(); // 清空所有 session.evict(user);// 清除指定 user = (User) session.get(User.class, 5); session.getTransaction().commit(); // session.flush(); session.close(); } @Test public void sessionTest() throws Exception { Session session1 = sf.openSession(); session1.beginTransaction(); Session session2 = sf.openSession(); session2.beginTransaction(); // user放入session1的缓存区 User user = (User) session1.get(User.class, 1); // user放入session2的缓存区 session2.update(user); // 修改对象 user.setUserName("New Name"); // 2条update session1.getTransaction().commit(); // session1.flush(); session1.close(); session2.getTransaction().commit(); // session2.flush(); session2.close(); } }
补充:
1.不同的session有自己的缓存区,
User1 u1 = Session1.get(User.class,1); 把u1对象放入session1的缓存 Session2.update(u1); 把u1放入session2的缓存 //修改对象, U1.setName(‘new Name’); 提交事务时候,生成2条update sql,分别更新不同的session缓存区对象(这种情况应该是同一个对象,如果是两个session获取那么应该是不同的两个值一样的对象)
2. list与iterator查询的区别?
list() :
一次把所有的记录都查询出来,
会放入缓存(会将对象分别放入缓存),但不会从缓存中获取数据(第二次执行list仍然执行查询数据库)
Iterator():
N+1查询;N表示所有的记录总数 即会先发送一条语句查询所有记录的主键(1), 再根据每一个主键再去数据库查询(N)! 会放入缓存(只会将查询的对象进行缓存),也会从缓存中取数据!(第二执行iterator仍然会执行查询所有的主键,主键对应的对象会从缓存中取)
测试实例:
public class Test{ private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(User.class) // 测试时候使用 .buildSessionFactory(); } //1. list 方法 @Test public void list() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // HQL查询 Query q = session.createQuery("from User "); // list()方法 List<User> list = q.list(); for (int i=0; i<list.size(); i++){ System.out.println(list.get(i)); } session.getTransaction().commit(); session.close(); } //2. iterator 方法 @Test public void iterator() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // HQL查询 Query q = session.createQuery("from User "); // iterator()方法 Iterator<User> it = q.iterate(); while(it.hasNext()){ // 得到当前迭代的每一个对象 User user = it.next(); System.out.println(user); } session.getTransaction().commit(); session.close(); } //3. 缓存 @Test public void cache() throws Exception { Session session = sf.openSession(); session.beginTransaction(); /**************执行2次list***************** Query q = session.createQuery("from User"); List<User> list = q.list(); // 【会放入?】 for (int i=0; i<list.size(); i++){ System.out.println(list.get(i)); } System.out.println("=========list==========="); list = q.list(); // 【会放入?】 for (int i=0; i<list.size(); i++){ System.out.println(list.get(i)); } /**************执行2次iteator******************/ Query q = session.createQuery("from User "); Iterator<User> it = q.iterate(); // 【放入缓存】 while(it.hasNext()){ User user = it.next(); System.out.println(user); } System.out.println("==========iterate==========="); it = q.iterate(); // 【也会从缓存中取】 while(it.hasNext()){ User user = it.next(); System.out.println(user); } session.getTransaction().commit(); session.close(); } // 测试list方法会放入缓存 @Test public void list_iterator() throws Exception { Session session = sf.openSession(); session.beginTransaction(); // 得到Query接口的引用 Query q = session.createQuery("from User "); // 先list 【会放入缓存,但不会从缓存中获取数据】 List<User> list = q.list(); for (int i=0; i<list.size(); i++){ System.out.println(list.get(i)); } // 再iteraotr (会从缓存中取) Iterator<User> it = q.iterate(); while(it.hasNext()){ User user = it.next(); System.out.println(user); } session.getTransaction().commit(); session.close(); } }
1.list方法执行的查询语句:(只执行一次sql,一次性查询出所有记录)

2.iterator方法执行的查询语句:(首先查询出所有id,然后再分别查询出所有记录)

3.执行两次list方法,执行2条sql语句:(每次都是一次性查询出所有记录,缓存的却是单个对象,所以执行两次sql语句)

4.执行两次iterator:(第二次执行时候,之后执行查询所有id,单个对象都从缓存中取)

5.先执行list在执行iterator(单个取的时候,取得的list执行时候缓存的单个对象)

懒加载:
1.类的懒加载,在使用类的属性才加载
2.类的属性集合的懒加载,该属性集合是关联的其他表的数据,在使用该集合属性才加载。
get、load方法区别?
get: 及时加载,只要调用get方法立刻向数据库查询
load:默认使用懒加载,当用到数据的时候才向数据库查询。
当采用load方法时候,可以通过配置的lazy属性不采用懒加载的方式(默认省略时,lazy是true表示采用懒加载;false时同get方法效果):

懒加载:(lazy)
概念:当用到数据的时候才向数据库查询,这就是hibernate的懒加载特性。
目的:提供程序执行效率!
当使用懒加载时,如果session关闭后,使用懒加载数据报错
为什么要关闭session:因为数据库的连接数是有限制,关闭session,相当释放连接。
出现的异常是:
org.hibernate.LazyInitializationException: could not initialize proxy - no Session
解决session关闭后不能使用懒加载数据的问题?
方式1:先使用一下数据
//dept.getDeptName();
方式2:强迫代理对象初始化
Hibernate.initialize(dept);
方式3:关闭懒加载
设置lazy=false;
方式4: 在使用数据之后,再关闭session!
实例:
Dept.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.itcast.b_one2Many"> <class name="Dept" table="t_dept" > <id name="deptId"> <generator class="native"></generator> </id> <property name="deptName" length="20"></property> <!-- 集合属性,默认使用懒加载 lazy true 懒加载 extra 懒加载(智能) false 关闭懒加载 --> <set name="emps" lazy="extra"> <key column="dept_id"></key> <one-to-many class="Employee"/> </set> </class> </hibernate-mapping>
Dept.java
public class Dept { private int deptId; private String deptName; // 【一对多】 部门对应的多个员工 private Set<Employee> emps = new HashSet<Employee>(); public int getDeptId() { return deptId; } public void setDeptId(int deptId) { this.deptId = deptId; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } public Set<Employee> getEmps() { return emps; } public void setEmps(Set<Employee> emps) { this.emps = emps; }
Employee.java
private int empId; private String empName; private double salary; // 【多对一】员工与部门 private Dept dept;; public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Dept getDept() { return dept; } public void setDept(Dept dept) { this.dept = dept; }
Employee.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="cn.itcast.b_one2Many"> <class name="Employee" table="t_employee"> <id name="empId"> <generator class="native"></generator> </id> <property name="empName" length="20"></property> <property name="salary" type="double"></property> <many-to-one name="dept" column="dept_id" class="Dept"></many-to-one> </class> </hibernate-mapping>
测试:
Session session = sf.openSession(); session.beginTransaction(); Dept dept = new Dept(); // get: 及时查询 // dept = (Dept) session.get(Dept.class, 9); // System.out.println(dept.getDeptName()); // load,默认懒加载, 及在使用数据的时候,才向数据库发送查询的sql语句! dept = (Dept)session.load(Dept.class, 9);
//如果不使用下面处理方式,关闭session,再获取该对象对应的数据会报错 // 方式1: 先使用一下数据 //dept.getDeptName();//此时才查询数据库 // 方式2:强迫代理对象初始化 Hibernate.initialize(dept);//此时才查询数据库 // 方式3:关闭懒加载 ;类的映射配置lazy=false session.getTransaction().commit(); session.close(); // 在这里使用 System.out.println(dept.getDeptName());//
上面是类的懒加载,还有一种类集合属性的懒加载:
Session session = sf.openSession(); session.beginTransaction();
//默认是不会查询集合属性的数据(默认是懒加载) Dept dept = (Dept) session.get(Dept.class, 10); System.out.println(dept.getDeptName()); System.out.println("------");
//默认查询属性集合的数据是所有记录而不是数量 System.out.println(dept.getEmps().isEmpty()); // 此时才执行SQL(查询employ表的数据) session.getTransaction().commit(); session.close();
可以通过配置lazy属性来设置是否懒加载

lazy 值的含义:
true 使用懒加载 false 关闭懒加载,意味查询类的数据时候会同时获取关联的所以纪录数据 extra (在集合数据懒加载时候提升效率) 在真正使用数据的时候才向数据库发送查询的sql; 如果调用集合的size()/isEmpty()方法,只是统计,不真正查询数据!
当lazy=extra,执行dept.getEmps()的size()/isEmpty()方法,查询的只是数量

当具体用到数据
System.out.println(dept.getEmps());
才会查询所有的纪录:


浙公网安备 33010602011771号