在hibernate中session缓存作为一级缓存,是事务缓存;SessionFactory缓存是二级缓存,是hibernate管理的进程缓存
要使用二级缓存,首先要在hibernate.cfg.xml中进行二级缓存的配置信息
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="dialect">
org.hibernate.dialect.MySQLDialect
</property>
<property name="hibernate.connection.driver_class">
com.mysql.jdbc.Driver
</property>
<property name="hibernate.connection.url">
jdbc:mysql://localhost:3306/hibernate_example_01
</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123</property>
<property name="show_sql">true</property>
<property name="format_sql">false</property>
<property name="hbm2ddl.auto">update</property>
<!-- <mapping resource="hibernate_a_helloword/User.hbm.xml" /> -->
<!--
设置默认的事务隔离级别:
隔离级别 对应的整数表示
READ UNCOMMITED 1
READ COMMITED 2
REPEATABLE READ 4
SERIALIZEABLE 8
-->
<property name="connection.isolation">2</property>
<!-- C3P0连接池设定-->
<!-- 使用c3p0连接池 配置连接池提供的供应商-->
<property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider </property>
<!--在连接池中可用的数据库连接的最少数目 -->
<property name="c3p0.min_size">5</property>
<!--在连接池中所有数据库连接的最大数目 -->
<property name="c3p0.max_size">20</property>
<!--设定数据库连接的过期时间,以秒为单位,
如果连接池中的某个数据库连接处于空闲状态的时间超过了timeout时间,就会从连接池中清除 -->
<property name="c3p0.timeout">120</property>
<!--每3000秒检查所有连接池中的空闲连接 以秒为单位-->
<property name="c3p0.idle_test_period">3000</property>
<!-- 使用二级缓存,默认是未打开的。 -->
<!-- 指定要使用的缓存的提供商,这也就打开了二级缓存
<property name="cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
-->
<property name="cache.provider_class">org.hibernate.cache.EhCacheProvider</property>
<!-- 开启使用查询缓存 -->
<property name="cache.use_query_cache">true</property>
<!-- 指定要使用二级缓存的实体类 -->
<class-cache usage="read-write" class="hibernate_a_example.Employee"/>
<class-cache usage="read-write" class="hibernate_a_example.Department"/>
<collection-cache usage="read-write" collection="hibernate_a_example.Department.employees"/>
</session-factory>
</hibernate-configuration>
然后就可以在类实现二级缓存
package hibernate_a_example;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class App {
private static SessionFactory sessionFactory = new Configuration()//
.configure()//
.addClass(Department.class)// 添加Hibernate实体类(加载对应的映射文件)
.addClass(Employee.class)// 添加Hibernate实体类(加载对应的映射文件)
.buildSessionFactory();
// 测试一级缓存(Session缓存)
@Test
public void testSessionCache() throws Exception {
// ===================== 第1个Session
Session session = sessionFactory.openSession();
session.beginTransaction();
Employee employee = (Employee) session.get(Employee.class, 1); // 获取
session.getTransaction().commit();
session.close();
// ===================== 第2个Session
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
Employee employee2 = (Employee) session2.get(Employee.class, 1); // 获取
session2.getTransaction().commit();
session2.close();
}
// 测试二级缓存
@Test
public void testSecondCache() throws Exception {
// ===================== 第1个Session
Session session = sessionFactory.openSession();
session.beginTransaction();
Department department = (Department) session.get(Department.class, 1); // 获取
System.out.println(department.getName());
System.out.println(department.getEmployees());
session.getTransaction().commit();
session.close();
// ===================== 第2个Session
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
Department department2 = (Department) session2.get(Department.class, 1); // 获取
System.out.println(department2.getName());
System.out.println(department2.getEmployees());
session2.getTransaction().commit();
session2.close();
}
// 测试查询缓存
// 当使用Query.list()时,默认不会使用二级缓存
@Test
public void testQueryCache() throws Exception {
// ===================== 第1个Session
Session session = sessionFactory.openSession();
session.beginTransaction();
List<Employee> list = session.createQuery("FROM Employee e WHERE e.id<10").list();
System.out.println(list);
Employee employee5 = (Employee) session.get(Employee.class, 5);
System.out.println(employee5);
session.getTransaction().commit();
session.close();
// ===================== 第2个Session
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
List<Employee> list2 = session2.createQuery("FROM Employee e WHERE e.id<10").list();
System.out.println(list2);
session2.getTransaction().commit();
session2.close();
}
// 测试查询缓存
// 在使用HQL方式的查询时,如果用iterate()方法,就会使用缓存。
// 因为这个方法是先查询所有符合条件的id集合,再一个一个的按id查找数据,就能用上缓存了。
// 但这个方法会有N+1次查询的问题,提升性能有限,不太常用。
@Test
public void testQueryCache2() throws Exception {
// ===================== 第1个Session
Session session = sessionFactory.openSession();
session.beginTransaction();
Iterator<Employee> iterator = session.createQuery("FROM Employee e WHERE e.id<8").iterate();
while (iterator.hasNext()) {
Employee e = iterator.next();
System.out.println(e);
}
Employee employee5 = (Employee) session.get(Employee.class, 5);
System.out.println(employee5);
session.getTransaction().commit();
session.close();
System.out.println("\n------------------\n");
// ===================== 第2个Session
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
Iterator<Employee> iterator2 = session2.createQuery("FROM Employee e WHERE e.id<10").iterate();
while (iterator2.hasNext()) {
Employee e = iterator2.next();
System.out.println(e);
}
session2.getTransaction().commit();
session2.close();
}
@Test
public void testQueryCache3() throws Exception {
// ===================== 第1个Session
Session session = sessionFactory.openSession();
session.beginTransaction();
List list = session.createQuery("FROM Employee e WHERE e.id<18")//
.setCacheable(true)// 是否使用查询缓存,需要在hibernate.cfg.xml中开启查询缓存才行
.list();
System.out.println(list);
session.getTransaction().commit();
session.close();
System.out.println("\n------------------\n");
// ===================== 第2个Session
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
List list2 = session2.createQuery("FROM Employee e WHERE e.id<18")//
.setCacheable(true)// 是否使用查询缓存
.list();
System.out.println(list2);
session2.getTransaction().commit();
session2.close();
}
// 测试Update与 Delete格式的HQL语对二级缓存的影响
// 会让二级缓存中相关的数据失效,下次使用这些数据时会重新到数据库中加载
@Test
public void testUpdateTimestampCache() throws Exception {
// ===================== 第1个Session
Session session = sessionFactory.openSession();
session.beginTransaction();
// 先获取
Employee employee = (Employee)session.get(Employee.class, 1);
System.out.println(employee.getName());
// 再直接更新DB
session.createQuery("UPDATE Employee e SET e.name=? WHERE id=?")//
.setParameter(0, "测试")//
.setParameter(1, 1)//
.executeUpdate();// 执行
// 再显示这个员工的名称
System.out.println(employee.getName());
session.getTransaction().commit();
session.close();
System.out.println("\n------------------\n");
// ===================== 第2个Session
Session session2 = sessionFactory.openSession();
session2.beginTransaction();
Employee employee2 = (Employee)session2.get(Employee.class, 1);
System.out.println(employee2.getName());
session2.getTransaction().commit();
session2.close();
}
}
要使用也是要在cfg.xml中配置绑定的线程信息
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory name="foo">
<!-- 配置数据库信息 -->
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="connection.url">jdbc:mysql:///hibernate_20120328</property>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<!-- 其他配置 -->
<property name="hibernate.show_sql">true</property>
<property name="hibernate.format_sql">false</property>
<property name="hbm2ddl.auto">update</property>
<!-- 当配置为thread时,SessionFactory的getCurrentSession()方法就能使用了 -->
<property name="current_session_context_class">thread</property>
</session-factory>
</hibernate-configuration>
在类中实现
package hibernate_a_example;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class App2 {
private static SessionFactory sessionFactory = new Configuration()//
.configure("hibernate_a_example/myhibernate.cfg.xml")//
.buildSessionFactory();
// 要想使用SessionFactory.getCurrentSession()方法
// 需要在Hibernate主配置文件中配置current_session_context_class项。
// getCurrentSession()方法:
// >> 去指定的上下文中(如thread)查找绑定的Session对象,如果有就返回。
// >> 如果没有,就创建一个并绑定好,然后返回
// >> openSession()只是开启一个新的Session,不会做绑定和查找操作。
@Test
public void testSession() throws Exception {
Session session1 = sessionFactory.getCurrentSession();
Session session2 = sessionFactory.getCurrentSession();
System.out.println(session1 != null); // true
System.out.println(session1 == session2); // true
}
// 当使用getCurrentSession时,Hibernate会在提交或回滚后自动的关闭Session
@Test
public void testSessionClose() throws Exception {
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
System.out.println("使用Session做XXX操作");
session.getTransaction().commit();
//session.close(); // 当使用getCurrentSession时,就不能再自己关闭了
}
@Test
public void testSession2() throws Exception {
Session session1 = sessionFactory.openSession();
Session session2 = sessionFactory.openSession();
System.out.println(session1 != null); // true
System.out.println(session1 == session2); // false
}
@Test
public void testSession3() throws Exception {
Session session2 = sessionFactory.getCurrentSession();
Session session1 = sessionFactory.openSession();
System.out.println(session1 != null); // true
System.out.println(session1 == session2); // false
}
}
在使用了二级缓存,session所要查询的对象在一个事务中是同一个事务,除非提交了事务或者关闭了事务,会产生另一个session对象,opensession产生的session对象每次产生的都是新的session,在一个事务中不是唯一