hibernate二级缓存(一)一级缓存与二级缓存
hibernate二級緩存(一)一級緩存與二級緩存
1.hibernate一級緩存
hibernate的一級緩存是session級別的緩存,一級緩存hibernate默認(rèn)啟用且不能被卸載,一個事務(wù)內(nèi)有效。
 特點(diǎn):
使用一級緩存的目的是為了減少對數(shù)據(jù)庫的訪問次數(shù),從而提升hibernate的執(zhí)行效率;(當(dāng)執(zhí)行一次查詢操作的時候,執(zhí)行第二次查詢操作,先檢查緩存中是否有數(shù)據(jù),如果有數(shù)據(jù)就不查詢數(shù)據(jù)庫,直接從緩存中獲取數(shù)據(jù));
Hibernate中的一級緩存,也叫做session的緩存,它可以在session范圍內(nèi)減少數(shù)據(jù)庫的訪問次數(shù),只在session范圍內(nèi)有效,session關(guān)閉,一級緩存失敗;
一級緩存的特點(diǎn),只在session范圍有效,作用時間短,效果不是特別明顯,在短時間內(nèi)多次操作數(shù)據(jù)庫,效果比較明顯。
當(dāng)調(diào)用session的save/saveOrUpdate/get/load/list/iterator方法的時候,都會把對象放入session緩存中;
session的緩存是由hibernate維護(hù)的,用戶不能操作緩存內(nèi)容;如果想操作緩存內(nèi)容,必須通過hibernate提供的evict/clear方法操作
緩存相關(guān)的方法(在什么情況下使用上面方法呢?批量操作情況下使用,如Session.flush();先與數(shù)據(jù)庫同步,Session.clear();再清空一級緩存內(nèi)容):
session.flush();讓一級緩存與數(shù)據(jù)庫同步;session.evict();清空一級緩存中指定的對象;session.clear();清空一級緩存中所有的對象;綜上: 一級緩存的生命周期和session的生命周期一致,當(dāng)前session一旦關(guān)閉,一級緩存就消失了,因此一級緩存也叫session級的緩存或事務(wù)級緩存,一級緩存只存實(shí)體對象,它不會緩存一般的對象屬性(查詢緩存可以),即當(dāng)獲得對象后,就將該對象緩存起來,如果在同一session中再去獲取這個對象時,它會先判斷在緩存中有沒有該對象的id,如果有則直接從緩存中獲取此對象,反之才去數(shù)據(jù)庫中取,取的同時再將此對象作為一級緩存處理。
2.二級緩存
Hibernate的二級緩存又稱為"SessionFactory的緩存",由于SessionFactory對象的生命周期和應(yīng)用的整個過程對應(yīng),他是可選的,是一個可配置的插件,默認(rèn)情況下SessionFactory不會啟用這個插件。
 由于二級緩存是被各session共享的,那么多個事務(wù)或者說線程同時訪問修改二級緩存可能會會造成數(shù)據(jù)不一致問題。所以二級緩存只適合多讀少寫的場景。
那么什么樣的數(shù)據(jù)適合放在二級緩存中呢?
- 多讀少寫的數(shù)據(jù)
- 不是很重要的數(shù)據(jù)
- 常量數(shù)據(jù)
什么樣的數(shù)據(jù)不適合放在二級緩存中呢?
- 經(jīng)常被修改的數(shù)據(jù)
- 絕對不允許出現(xiàn)并發(fā)訪問的數(shù)據(jù)。如財(cái)務(wù)數(shù)據(jù),絕對不允許出現(xiàn)并發(fā)
- 與其他應(yīng)用共享的數(shù)據(jù)
3. 二級緩存的配置
這里只展示純hibernate的二級緩存配置,如果要如spring結(jié)合,請參考spring sessionFactory配置里面的hibernate二級緩存參數(shù)。
 下面的配置是基于hibernate5.3.7.Final版本
3.1 SessionFactory的配置
該版本的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><!-- 數(shù)據(jù)庫連接配置 --><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><!-- 數(shù)據(jù)庫連接池的大小 --><property name="connection.pool_size">5</property><!-- 每次從數(shù)據(jù)庫中取出并放到JDBC的Statement中的記錄條數(shù)。Fetch Size設(shè)的越大,讀數(shù)據(jù)庫的次數(shù)越少,速度越快,Fetch Size越小,讀數(shù)據(jù)庫的次數(shù)越多,速度越慢--><property name="jdbc.fetch_size">50</property><!--批量插入,刪除和更新時每次操作的記錄數(shù)。Batch Size越大,批量操作的向數(shù)據(jù)庫發(fā)送Sql的次數(shù)越少,速度就越快,同樣耗用內(nèi)存就越大--><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><!-- 在啟動時根據(jù)配置更新數(shù)據(jù)庫 --><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"/><!-- 注冊我們的實(shí)體映射類--></session-factory> </hibernate-configuration>3.2 基本的代碼示例
有了SessionFactory后通過session進(jìn)行增刪改查等操作
public class Main {public static void main(String[] args) {SessionFactoryUtil sessionFactoryUtil = new SessionFactoryUtil();SessionFactory sessionFactory = sessionFactoryUtil.getSessionFactory();//1.查詢單個實(shí)體doExecute(sessionFactory, new HibernateExecuteCallBack() {@Overridepublic void execute(Session session) {Event event = session.get(Event.class, 7L);System.out.println(event);}});//2.查詢單個實(shí)體doExecute(sessionFactory, new HibernateExecuteCallBack() {@Overridepublic 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的整個執(zhí)行流程的模版代碼,HibernateExecuteCallBack 回調(diào)接口將實(shí)際執(zhí)行操作分離,整個過程類似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;@Columnprivate 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;}@Overridepublic String toString() {return "Event{" +"id=" + id +", title='" + title + '\'' +", date=" + date +'}';} }Event的代碼隨意,是通過注解配置實(shí)體,但是必須注意在hibernate.cfg.xml里面必須配置:
<mapping class="com.foo.model.Event"/><!-- 注冊我們的實(shí)體映射類-->3.2 二級緩存的配置
在上面的配置里面其實(shí)已經(jīng)加上了二級緩存
<!--是否啟用二級緩存--><property name="hibernate.cache.use_second_level_cache">true</property><!--緩存的具體實(shí)現(xiàn)--><property name="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.internal.EhcacheRegionFactory</property><!--以頻繁的讀操作為代價(jià), 優(yōu)化二級緩存來最小化寫操作--><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來作為二級緩存的具體實(shí)現(xiàn)。當(dāng)然也可以自己實(shí)現(xiàn)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 );- CacheConcurrencyStrategy.None 不使用緩存
- CacheConcurrencyStrategy.READ_ONLY:只讀模式,在此模式下,如果對數(shù)據(jù)進(jìn)行更新操作,會拋出異常。
- CacheConcurrencyStrategy.READ_WRITE:讀寫模式在更新緩存的時候會對緩存里的數(shù)據(jù)加鎖,其他事物如果去取相應(yīng)緩存中的數(shù)據(jù),發(fā)現(xiàn)被鎖了,直接去數(shù)據(jù)庫中取。
- CacheConcurrencyStrategy.NONSTRICT_READ_WRITE:不嚴(yán)格的讀寫模式則不會對緩存數(shù)據(jù)加鎖
- CacheConcurrencyStrategy.TRANSACTIONAL:事務(wù)模式指緩存支持事務(wù),當(dāng)事務(wù)回滾,緩存也回滾,只支持JTA環(huán)境
一切配置完畢,下面來看下具體的執(zhí)行結(jié)果,
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里面,我們看到配置了緩存之后只發(fā)送了一條sql語句。代表緩存配置成功。在后面我們將具體講解hibernate二級緩存的實(shí)現(xiàn)原理并自己用map實(shí)現(xiàn)一個簡單的RegionFactory。
總結(jié)
以上是生活随笔為你收集整理的hibernate二级缓存(一)一级缓存与二级缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 计算机组成原理试题解析答案,计算机组成原
- 下一篇: 矩阵分析与应用(二)——内积与范数
