Hibernate进阶之SessionFactory二级缓存

本文详细介绍了Hibernate中SessionFactory二级缓存的工作原理与配置方法,包括如何启用缓存、配置实体和集合的缓存策略,以及如何利用HQL查询缓存提高应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇介绍了hql语句的认识,接下来认识sessionFactory二级缓存。

首先总结一下下面将要介绍知识:

一)SessionFactory二级缓存

   (1)在默认情况下,SessionFactory二级缓存只存放连接数据库的相关信息,和映射文件信息,不能存放持久化对象
   (2)在默认情况下,session.get(),每执行一次,都要查询数据库,即生成select语句
   (3)启用SessionFactory二级缓存,使其也能存持久化对象
   (4) 在默认情况下,session.get(Customer.class,1),按如下顺序查找:
       (1)在session一级缓存中查询对象,如果查到,直接返回。
       (2)如果查不到,再查询数据库表,如果查到了,将春封装成PO对象返回,同时存于session一级缓存中,以备后用

   (5)当启用SessionFacotry二级缓存后,session.get/load(Customer.class,1),则按如下顺序查找:
       (1)在session一级缓存中查询对象,如果查到,直接返回。
       (2)如果查不到,再查询sessionfactory二级缓存,如果查询到了则返回,并复制一份到session一级缓存中,以备后用
       (3)如果在sessionfactory二级缓存没有找到,查询数据库表,如果查到了,将其封装成PO对象返回,同时存于session
            和sessionfactory级缓存中,以备后用

   (6)如何启用SessionFactory二级缓存
        hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider

   (7)将Customer对象存入二级缓存
Customer.hbm.xml文件
        <class name="Customer" table="CUSTOMERS">
 <cache usage="read-only"/>
        </class>

   (8)将Customer对象和Order集合存入二级缓存
Customer.hbml.xml文件
        <set name="ordetSet" table="ORDERS">
 <cache usage="read-only"/>
        </set>
        Order.hbm.xml文件
        <class name="Order" table="ORDERS">
 <cache usage="read-only"/>
        </class>

   (9)get()/load()使用二级缓存中的普通缓存区

  (10)HQL使用二级缓存中的查询缓存区,即list()/uniqueResult()使用二级缓存中的查询缓存区,如何启用查询缓存区
         hibernate.cache.use_query_cache=true
         session.createQuery("FROM Customer c WHERE c.id=1").setCacheable(true).list();
         session.createQuery("FROM Customer c WHERE c.id=1").setCacheable(true).uniqueResult();

  (11)session.update()会同步更新一级和二级缓存区

综上所述:以空换时

接下来用实例来学习二级缓存:

首先写两个实体类Customer,Order:

Customer:

package example.one2many_single;

import java.util.LinkedHashSet;
import java.util.Set;

/**
 * 客户(一方)
 * @author Administrator
 *
 */
public class Customer {

	private Integer id;//对应表的主键
	private String name;
	private Integer age;
	private Set<Order> orderSet=new LinkedHashSet<Order>();//关联属性
	public Customer() {
	}
	public Customer(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	public Set<Order> getOrderSet() {
		return orderSet;
	}
	public void setOrderSet(Set<Order> orderSet) {
		this.orderSet = orderSet;
	}
	
}

Order类:

package example.one2many_single;
/**
 * 订单(多的一方)
 * @author Administrator
 *
 */
public class Order {

	private Integer id;
	private String OrderNo;//订单编号
	private Integer price;//价格
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public String getOrderNo() {
		return OrderNo;
	}
	public void setOrderNo(String orderNo) {
		OrderNo = orderNo;
	}
	public Integer getPrice() {
		return price;
	}
	public void setPrice(Integer price) {
		this.price = price;
	}
	public Order(String orderNo, Integer price) {
		super();
		OrderNo = orderNo;
		this.price = price;
	}
	public Order() {
	}
	
}

第二步写配置文件hibernate.properties:

#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect
#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.driver_class=com.mysql.jdbc.Driver
hibernate.connection.url=jdbc:mysql://127.0.0.1:3306/example_db
hibernate.connection.username=root
hibernate.connection.password=****
hibernate.show_sql=true
hibernate.hbm2ddl.auto=update
hibernate.cache.provider_class=org.hibernate.cache.HashtableCacheProvider

第三步写映射配置文件CustomerOrder.hbm.xml:只是把customer写入二级缓存,是只能读的

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example.sessionFactory">
	<class name="Customer" table="customers">
	   <cache usage="read-only"/>
		<id name="id" column="id" type="int">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name" type="string"></property>
		<property name="age" column="age" type="int"></property>
		<!-- set标签用于映射单向一对多
			name表示单方的关联属性
			table表示多方对应表的名字
			key-cloumn表示多方对应表的外键
			one-to-many-class表示单方关联属性中的每个元素的类型
		 -->
		 <set name="orderSet" table="orders" cascade="all" inverse="true">
		 	<key column="customers_id"></key>
		 	<one-to-many class="Order"/>
		 </set>
	</class>
	<!-- 映射类的多方 -->
	<class name="Order" table="Orders">
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="orderNo" column="orderNo"></property>
		<property name="price" column="price"></property>
		<many-to-one name="customer" column="customers_id"></many-to-one>
	</class>
</hibernate-mapping>

package example.sessionFactory;

import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.Test;

import example.utils.HibernateUtils;

public class CustomerDao {

	@Test
	public void test01(){
		Session session = HibernateUtils.getSession();
		Transaction t = session.getTransaction();
		try{
			t.begin();
			Customer c= (Customer) session.get(Customer.class, 1);
			for(Order o:c.getOrderSet()){
				System.out.println(o.getOrderNo()+","+o.getPrice());
			}
			session.clear();//清空一级缓存
			System.out.println("-----------------");
			c = (Customer) session.get(Customer.class,1);
			for(Order o : c.getOrderSet()){
				System.out.println(o.getOrderNo()+":"+o.getPrice());
			}
			t.commit();
		}catch (Exception e) {
			// TODO: handle exception
			t.rollback();
			e.printStackTrace();
			
		}
	}
}

运行结果:
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_, customer0_.age as age0_0_ from customers customer0_ where customer0_.id=?
Hibernate: select orderset0_.customers_id as customers4_0_1_, orderset0_.id as id1_, orderset0_.id as id1_0_, orderset0_.orderNo as orderNo1_0_, orderset0_.price as price1_0_, orderset0_.customers_id as customers4_1_0_ from Orders orderset0_ where orderset0_.customers_id=?
order2011,130
order2012,130
-----------------
Hibernate: select orderset0_.customers_id as customers4_0_1_, orderset0_.id as id1_, orderset0_.id as id1_0_, orderset0_.orderNo as orderNo1_0_, orderset0_.price as price1_0_, orderset0_.customers_id as customers4_1_0_ from Orders orderset0_ where orderset0_.customers_id=?
order2011:130
order2012:130
根据结果我们可以分析到,使用get立即查询数据时,以及对象导航查询有两条sql语句产生,当把一级缓存session清空掉之后,只有查询订单一条sql语句产生,这个说明我们此时查询的顾客是从sessionFactory二级缓存查到customer数据的,然而订单查询没有在映射配置文件中配置存入二级缓存,所以就会从数据库中查询。

那么接下来测试把订单也存入二级缓存:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="example.sessionFactory">
	<class name="Customer" table="customers">
		<cache usage="read-only"/>
		<id name="id" column="id" type="int">
			<generator class="native"></generator>
		</id>
		<property name="name" column="name" type="string"></property>
		<property name="age" column="age" type="int"></property>
		<!-- set标签用于映射单向一对多
			name表示单方的关联属性
			table表示多方对应表的名字
			key-cloumn表示多方对应表的外键
			one-to-many-class表示单方关联属性中的每个元素的类型
		 -->
		 <set name="orderSet" table="orders" cascade="all" inverse="true">
		 <cache usage="read-only"/>
		 	<key column="customers_id"></key>
		 	<one-to-many class="Order"/>
		 </set>
	</class>
	<!-- 映射类的多方 -->
	<class name="Order" table="Orders">
	<cache usage="read-only"/>
		<id name="id" column="id">
			<generator class="native"></generator>
		</id>
		<property name="orderNo" column="orderNo"></property>
		<property name="price" column="price"></property>
		<many-to-one name="customer" column="customers_id"></many-to-one>
	</class>
</hibernate-mapping>

测试类跟上面的一样。

查询结果如下:

Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_, customer0_.age as age0_0_ from customers customer0_ where customer0_.id=?
Hibernate: select orderset0_.customers_id as customers4_0_1_, orderset0_.id as id1_, orderset0_.id as id1_0_, orderset0_.orderNo as orderNo1_0_, orderset0_.price as price1_0_, orderset0_.customers_id as customers4_1_0_ from Orders orderset0_ where orderset0_.customers_id=?
order2011,130
order2012,130
-----------------
order2012:130
order2011:130

下面学习HQL使用二级缓存中的查询缓存区:

首先在配置文件hibernate.properties加入:

 hibernate.cache.use_query_cache=true
接下来写测试类:

@Test
	public void test2(){
		Session session = HibernateUtils.getSession();
		Transaction t = session.getTransaction();
		try{
			t.begin();

			String hql = "from Customer c where c.id = 1";
			Query query = session.createQuery(hql);
			query.setCacheable(true);//启用查询缓冲区
			Customer c = (Customer) query.uniqueResult();
			for(Order o : c.getOrderSet()){
				System.out.println(o.getOrderNo()+":"+o.getPrice());
			}
			
			session.clear();

			hql = "from Customer c where c.id = 1";
			query = session.createQuery(hql);
			query.setCacheable(true);
			c = (Customer) query.uniqueResult();
			for(Order o : c.getOrderSet()){
				System.out.println(o.getOrderNo()+":"+o.getPrice());
			}
			
			t.commit();
			
		}catch(Exception e){
			e.printStackTrace();
			t.rollback();
		}finally{
			HibernateUtils.closeSession();
		}
	}

运行结果如下:

log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select customer0_.id as id0_, customer0_.name as name0_, customer0_.age as age0_ from customers customer0_ where customer0_.id=1
Hibernate: select orderset0_.customers_id as customers4_0_1_, orderset0_.id as id1_, orderset0_.id as id1_0_, orderset0_.orderNo as orderNo1_0_, orderset0_.price as price1_0_, orderset0_.customers_id as customers4_1_0_ from Orders orderset0_ where orderset0_.customers_id=?
order2012:130
order2011:130
order2011:130
order2012:130

从结果中我们可以看到从session.close()之后得到的数据是从二级缓存中得到的。

下面学习如何修改二级缓存中的数据:假设我们要修改customer中的数据:

在映射文件中把<cache usage="read-only"/>改为<cache usage="read-write"/>。

接下来我们写一个测试类:

@Test
	public void test3(){
		Session session = HibernateUtils.getSession();
		Transaction t = session.getTransaction();
		try{
			t.begin();

			Customer c = (Customer) session.get(Customer.class,1);					
			c.setName("小尼妞");
            session.update(c);
			t.commit();
			
		}catch(Exception e){
			e.printStackTrace();
			t.rollback();
		}finally{
			HibernateUtils.closeSession();
		}
	}

运行结果如下:

log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Hibernate: select customer0_.id as id0_0_, customer0_.name as name0_0_, customer0_.age as age0_0_ from customers customer0_ where customer0_.id=?
Hibernate: update customers set name=?, age=? where id=?




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值