大家好,又见面了,我是你们的朋友全栈君。
hibernate的一级缓存是session级别的缓存,一级缓存hibernate默认启用且不能被卸载,一个事务内有效。 特点:
综上: 一级缓存的生命周期和session的生命周期一致,当前session一旦关闭,一级缓存就消失了,因此一级缓存也叫session级的缓存或事务级缓存,一级缓存只存实体对象,它不会缓存一般的对象属性(查询缓存可以),即当获得对象后,就将该对象缓存起来,如果在同一session中再去获取这个对象时,它会先判断在缓存中有没有该对象的id,如果有则直接从缓存中获取此对象,反之才去数据库中取,取的同时再将此对象作为一级缓存处理。
Hibernate的二级缓存又称为”SessionFactory的缓存”,由于SessionFactory对象的生命周期和应用的整个过程对应,他是可选的,是一个可配置的插件,默认情况下SessionFactory不会启用这个插件。 由于二级缓存是被各session共享的,那么多个事务或者说线程同时访问修改二级缓存可能会会造成数据不一致问题。所以二级缓存只适合多读少写的场景。
那么什么样的数据适合放在二级缓存中呢?
什么样的数据不适合放在二级缓存中呢?
这里只展示纯hibernate的二级缓存配置,如果要如spring结合,请参考spring sessionFactory配置里面的hibernate二级缓存参数。 下面的配置是基于hibernate5.3.7.Final版本
该版本的SessionFactory获取的最新方式如下:
public class SessionFactoryUtil {
private SessionFactory sessionFactory;
public SessionFactoryUtil() {
setUp();
}
private void setUp() {
// A SessionFactory is set up once for an application!
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder()
.configure() // configures settings from hibernate.cfg.xml
.build();
try {
sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
} catch (Exception e) {
e.printStackTrace();
// The registry would be destroyed by the SessionFactory, but we had trouble building the SessionFactory
// so destroy it manually.
StandardServiceRegistryBuilder.destroy(registry);
}
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
}
registry 会自动加载resources路径下的hibernate.cfg.xml配置文件。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="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test</property>
<property name="connection.username">root</property>
<property name="connection.password">123456</property>
<!-- 数据库连接池的大小 -->
<property name="connection.pool_size">5</property>
<!-- 每次从数据库中取出并放到JDBC的Statement中的记录条数。Fetch Size设的越大,读数据库的次数越少,速度越快,Fetch Size越小,读数据库的次数越多,速度越慢-->
<property name="jdbc.fetch_size">50</property>
<!--批量插入,删除和更新时每次操作的记录数。Batch Size越大,批量操作的向数据库发送Sql的次数越少,速度就越快,同样耗用内存就越大-->
<property name="jdbc.batch_size">23</property>
<!-- SQL 方言 -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- 在控制台输出sql语句 -->
<property name="show_sql">true</property>
<!-- 在启动时根据配置更新数据库 -->
<property name="hbm2ddl.auto">update</property>
<!-- 二级缓存配置 -->
<property name="hibernate.cache.use_second_level_cache">true</property>
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>
<property name="hibernate.cache.use_minimal_puts">true</property>
<property name="hibernate.cache.use_query_cache">true</property>
<property name="hibernate.cache.region_prefix">customer-hibernate-cache</property>
<property name="hibernate.cache.default_cache_concurrency_strategy">nonstrict-read-write</property>
<mapping class="com.foo.model.Event"/><!-- 注册我们的实体映射类-->
</session-factory>
</hibernate-configuration>
有了SessionFactory后通过session进行增删改查等操作
public class Main {
public static void main(String[] args) {
SessionFactoryUtil sessionFactoryUtil = new SessionFactoryUtil();
SessionFactory sessionFactory = sessionFactoryUtil.getSessionFactory();
//1.查询单个实体
doExecute(sessionFactory, new HibernateExecuteCallBack() {
@Override
public void execute(Session session) {
Event event = session.get(Event.class, 7L);
System.out.println(event);
}
});
//2.查询单个实体
doExecute(sessionFactory, new HibernateExecuteCallBack() {
@Override
public void execute(Session session) {
Event event = session.get(Event.class, 7L);
System.out.println(event);
}
});
}
public static void doExecute(SessionFactory sessionFactory, HibernateExecuteCallBack executeCallBack) {
Session session = sessionFactory.openSession();
session.beginTransaction();
executeCallBack.execute(session);
session.getTransaction().commit();
session.close();
}
interface HibernateExecuteCallBack {
void execute(Session session);
}
上面的代码中首先得到一个sessionFactory ,然后通过doExecute封装session的整个执行流程的模版代码,HibernateExecuteCallBack 回调接口将实际执行操作分离,整个过程类似jdbcTemplate。
package com.foo.model;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import javax.persistence.*;
import java.util.Date;
/**
* @author JasonLin
* @version V1.0
* @date 2019/3/11
*/
@Entity
@Table(name = "event")
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Event {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private String title;
@Column(name = "_date")
private Date date;
public Event(){
}
public Event(String title, Date date) {
this.title = title;
this.date = date;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public String toString() {
return "Event{" +
"id=" + id +
", title='" + title + '\'' +
", date=" + date +
'}';
}
}
Event的代码随意,是通过注解配置实体,但是必须注意在hibernate.cfg.xml里面必须配置:
<mapping class="com.foo.model.Event"/><!-- 注册我们的实体映射类-->
在上面的配置里面其实已经加上了二级缓存
<!--是否启用二级缓存-->
<property name="hibernate.cache.use_second_level_cache">true</property>
<!--缓存的具体实现-->
<property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property>
<!--以频繁的读操作为代价, 优化二级缓存来最小化写操作-->
<property name="hibernate.cache.use_minimal_puts">true</property>
<!--是否使用查询缓存-->
<property name="hibernate.cache.use_query_cache">true</property>
<!--缓存的前缀-->
<property name="hibernate.cache.region_prefix">customer-hibernate-cache</property>
<!--缓存的策略-->
<property name="hibernate.cache.default_cache_concurrency_strategy">nonstrict-read-write</property>
这里我们使用的是EhcacheRegionFactory来作为二级缓存的具体实现。当然也可以自己实现RegionFactory,比如通过redis来作为hibernate的二级缓存。
hibernate.cache.default_cache_concurrency_strategy指定hibernate二级缓存策略,hibernate共有五种缓存策略
public enum CacheConcurrencyStrategy {
/**
* Indicates no concurrency strategy should be applied.
*/
NONE( null ),
/**
* Indicates that read-only strategy should be applied.
*
* @see AccessType#READ_ONLY
*/
READ_ONLY( AccessType.READ_ONLY ),
/**
* Indicates that the non-strict read-write strategy should be applied.
*
* @see AccessType#NONSTRICT_READ_WRITE
*/
NONSTRICT_READ_WRITE( AccessType.NONSTRICT_READ_WRITE ),
/**
* Indicates that the read-write strategy should be applied.
*
* @see AccessType#READ_WRITE
*/
READ_WRITE( AccessType.READ_WRITE ),
/**
* Indicates that the transaction strategy should be applied.
*
* @see AccessType#TRANSACTIONAL
*/
TRANSACTIONAL( AccessType.TRANSACTIONAL );
一切配置完毕,下面来看下具体的执行结果,
Hibernate: select event0_.id as id1_0_0_, event0_._date as _date2_0_0_, event0_.title as title3_0_0_ from event event0_ where event0_.id=?
Event{id=7, title='Our very first event!', date=2019-03-11 13:45:21.0}
Event{id=7, title='Our very first event!', date=2019-03-11 13:45:21.0}
由于我们的第一次操作是在不同的session里面,我们看到配置了缓存之后只发送了一条sql语句。代表缓存配置成功。在后面我们将具体讲解hibernate二级缓存的实现原理并自己用map实现一个简单的RegionFactory。
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/142230.html原文链接:https://javaforall.cn