Hibernate 二级缓存原理
缓存可以减少执行数据库查询时的网络调用。
一级缓存与会话(session)相关联,它是隐式实现的。一级缓存存在的时间只有会话对象存在的时间。一旦会话对象被终止/关闭,就没有缓存对象了。二级缓存在多个会话对象之间起作用,它与会话工厂(session factory)相关联。二级缓存对象对于会话工厂中的所有会话可用。这些缓存对象在特定的会话工厂关闭时终止。
实现二级缓存
为了使用二级缓存,我们需要添加以下依赖项。
<!-- https://mvnrepository.com/artifact/net.sf.ehcache/ehcache -->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>2.10.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.4.32.Final</version>
</dependency>
Note − hibernate ehcache版本号必须与hibernate版本号相同。
现在,我们需要添加hibernate配置文件,使hibernate能够连接到提供的数据库并使用二级缓存。
<!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>
<!-- JDBC Database connection settings -->
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/demo?useSSL=false</property>
<property name="connection.username">root</property>
<property name="connection.password">root</property>
<!-- JDBC connection pool settings ... using built-in test pool -->
<property name="connection.pool_size">4</property>
<!-- Echo the SQL to stdout -->
<property name="show_sql">true</property>
//caching properties
<property name="cache.use_second_level_cache">true</property>
<property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<!-- Select our SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create-drop</property>
<!-- name of annotated entity class -->
<mapping class="academy.company.Parent"/>
</session-factory>
</hibernate-configuration>
示例
默认情况下,Java中的所有实体都是非缓存的。因此,要启用实体的缓存,我们在我们的实体类Parent中使用@Cacheable和@Cache注解。
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
@Entity
@Table( name = " Employee")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
public class Parent {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
Long id;
@Column(name = "first_name")
String firstName;
@Column(name = "last_name")
String lastName;
}
Now, let’s check whether second level cache works:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class Main {
public static void main(String[] args) {
SessionFactory sessionFactory = new Configuration()
.configure("academy/company/hibernate.cfg.xml")
.buildSessionFactory();
Session session1 = sessionFactory.openSession();
Parent parent1 = session1.get(Parent.class, 4);
System.out.println(parent1.id + " " + parent1.firstName + " " + parent1.lastName);
session1.close();
Session session2 = sessionFactory.openSession();
Parent parent2 = session2.get(Parent.class, 4);
System.out.println(parent2.id + " " + parent2.firstName + " " + parent2.lastName);
session2.close();
}
}
输出
Hibernate: select parent0.id as id1, parent0.first_name as first_name1, parent0.last_name as last_name1 from Parent parent0 where parent0.id=?
1 Subash Chopra
1 Subash Chopra
我们可以清楚地从控制台看到,Hibernate在session1期间只执行了一次查询。当session2访问相同的查询时,不会进行网络调用来执行它。相反,由于我们使用了二级缓存,它将从session1中获取缓存对象。