为什么要用缓存?
目的:减少对数据库的访问次数!从而提升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(); 清空一级缓存中缓存的所有对象
在什么情况用上面方法?
批量操作使用使用:
Session.flush(); // 先与数据库同步
Session.clear(); // 再清空一级缓存内容
面试题1: 不同的session是否会共享缓存数据?
不会。
User1 u1 = Session1.get(User.class,1); 把u1对象放入session1的缓存
Session2.update(u1); 把u1放入session2的缓存
U1.setName(‘new Name’);
如果生成2条update sql, 说明不同的session使用不同的缓存区,不能共享。
面试题2: list与iterator查询的区别?
list()
一次把所有的记录都查询出来,
会放入缓存,但不会从缓存中获取数据
Iterator
N+1查询; N表示所有的记录总数
即会先发送一条语句查询所有记录的主键(1),
再根据每一个主键再去数据库查询(N)!
会放入缓存,也会从缓存中取数据!
package loaderman.a_status; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; import org.junit.Test; public class App2_cache { 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(); } }
package loaderman.a_status; import java.util.Iterator; import java.util.List; import org.hibernate.Query; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; import org.hibernate.classic.Session; import org.junit.Test; public class App3_list_iterator { private static SessionFactory sf; static { sf = new Configuration() .configure() .addClass(User.class) // 测试时候使用 .buildSessionFactory(); } /** * list与iterator区别 * 1. list 方法 * 2. iterator 方法 * 3. 缓存 * @throws Exception */ //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(); } }
package loaderman.a_status; public class User { private int userId; private String userName; public int getUserId() { return userId; } public void setUserId(int userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } @Override public String toString() { return "User [userId=" + userId + ", userName=" + userName + "]"; } }
<?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="loaderman.a_status"> <class name="User" table="t_user"> <id name="userId" column="id"> <generator class="native"></generator> </id> <property name="userName"></property> </class> </hibernate-mapping>