• 缓存


    缓存的物理介质通常是内存,而永久性数据存储源的物理介质通常是硬盘和磁盘,应用程序读写内存的速度显然比读写硬盘的速度快。若缓存中存放的数据量非常大,也会用硬盘作为缓存的物理介质。缓存的实现不仅需要作为物理介质的硬件,同时还需要用于管理缓存的并发访问和过期等策略的软件。 
    SessionFactory的缓存可分为两类:内置缓存和外置缓存。SessionFactory的内置缓存是Hibernate自带的,不可卸载。通常在Hibernate的初始化阶段,Hibernate会把映射元数据和预定义SQL语句存放到SessionFactory的内置缓存中,映射元数据是映射文件中数据的复制,而预定义SQL语句是Hibernate根据映射元数据推导出来的。SessionFactory的内置缓存是只读缓存,应用程序不能修改换成那种的映射元数据和预定义的SQL语句。因此SessionFactory无需进行内置缓存与映射文件的同步。SessionFactory的外置缓存是一个可配置的缓存插件。在默认的情况下,SessionFactory不会启用这个缓存插件。外置缓存中的数据是数据库数据的复制,外置缓存的物理介质可以是内存或硬盘。 
    Hibernate的Session缓存中存放的数据是数据库中的数据的复制。在数据库中数据表现为关系数据形式,而在Session缓存中表现为相互关联的对象。在读写数据库时,Session会负责这种形式的数据映射。Session会在某些时间点会按照缓存中的数据来同步更新数据库,这一过程被称为清理缓存。 

    缓存的范围可以分为三类:事务范围、进程范围和集群范围。 
    事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束,缓存也就结束生命周期。缓存的物理介质为内存。每个事务都有独自的缓存,缓存内的数据通常采用相互关联的对象形式。在同一个事务中,持久化类的每个对象具有唯一的OID。 
    进程范围:缓存被进程内的所有事务共享。这些事务有可能并发访问缓存,因此,必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖与进程的生命周期,当进程结束,缓存也就结束生命周期。进程范围的缓存可能会存放大量数据,它的物理介质可以是内存或硬盘。缓存内的数据既可以采用相互关联的对象模式,也可采用对象的散装数据形式。对象的散装数据有点类似于对象的序列化数据,但是把对象分解为散装数据的算法通常比对象的序列化的算法更快。 
    集群范围:在集群环境中,缓存被同一个机器或多个机器上的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程之间通过远程通信来保证缓存中数据的一致性,缓存中的数据通常采用对象的散装数据形式。 

    进程范围或集群范围缓存,即第二级缓存,会出现并发问题。对第二级缓存可以设定以下4种类型的并发访问策略,每一种策略对应一种事务隔离级别。 
    事务型(Transactional):仅在受管理环境中适用。它提供Repeatable Read事务隔离级别。对于经常被读但是很少被修改的数据,可以采用这种隔离类型。可以防止脏读和不可重复读。 
    读写型(Read-write):提供Read Committed事务隔离级别。仅在非集群的环境中适用。对于经常被读但是很少被修改的数据,可以采用这种隔离类型。可以防止脏读这类并发问题。 
    非严格读写型(Nonstrict-read-write):不保证缓存与数据库中数据的一致性。若存在两个事务同时访问缓存中相同数据的可能,必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被更改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。 
    只读型(Read-only):对于从来不会被修改的数据,若参考数据,可以使用这种并发访问策略。 
    符合以下条件的数据适合存放到第二级缓存: 
    很少被修改的数据 
    不是很重要的数据,允许出现偶尔的并发问题 
    不会被并发访问的数据 
    参考数据 
    参考数据是指供应用参考的常量数据,有以下几个特点:他的实例的数目有限、每个实例会被许多其他类的实例引用、它的实例极少或者从来不会被修改。 

    缓存配置器(Cache Provider)用于把具体的缓存实现软件与Hibernate集成。 

    当应用程序调用Session的save()、update()、saveOrUpdate()、load()和get()方法及调用Query查询接口的list()、iterate()和filter()方法时,若在Session的缓存中还不存在相应的对象,Hibernate就会把该对象加入到第一级缓存中。当清理缓存时,Hibernate会根据缓存中对象的状态变化来同步更新数据库。 
    Session为应用程序提供了两个管理缓存的方法: 
    evict(Object o):从缓存中清楚参数指定的持久化对象 
    clear():清空缓存中所有持久化对象 
    Session的evict()方法能够从缓存中清除特定的持久化对象,适用于一下情况: 
    不希望Session继续按照该对象的状态变化来同步更新数据库。 
    在批量更新或批量删除的场合,当更新或删除一个对象后,及时释放该对象占用的内存。 

    Hibernate的第二级缓存是进程或集群范围内的缓存,缓存中存放的是对象的散装数据。第二级缓存是可配置的插件,Hibernate允许选用以下类型的缓存插件: 
    EHCache:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,对Hibernate的查询缓存提供了支持。 
    OpenSymphonyOSCache:可作为进程范围内的缓存,存放数据的物理介质可以是内存或硬盘,提供了更夫的缓存数据过期策略,对Hibernate的查询缓存提供了支持。 
    SwarmCache:可作为集群范围内的缓存,但不支持Hibernate的查询缓存。 
    JBossCache:可作为集群范围内的缓存,支持事务性并发访问策略,对Hibernate的查询缓存提供了支持。 
                      各个缓存插件支持的并发访问策略 
    缓存插件                 只读型     非严格读写型      读写型      事务型 
    EHCache                    支持         支持          支持         否 
    OpenSymphonyOSCache        支持         支持          支持         否 
    SwarnCache                 支持         支持          否           否 
    JBossCache                 支持         否            否           否 
    为了把这些缓存插件集成到Hibernate中,Hibernate提供了org.hibernate.cacha.CacheProvider接口,它是缓存插件与Hibernate之间的适配器。Hibernate为以上缓存插件分别提供了内置的CacheProvider实现: 
    org.hibernate.cache.EhCacheProvider:EHCache插件的适配器 
    org.hibernate.cache.OSCacheProvider:OSCacheProvider插件的适配器 
    org.hibernate.cache.SwarmCacheProvider:SwarmCache插件的适配器 
    org.hibernate.cache.TreeCacheProvider:TreeCacheProvider插件的适配器 

    配置第二级缓存主要包含一下几个步骤: 
    1.选择需要使用第二级缓存的持久化类,设置它的第二级缓存的并发访问策略。Hibernate既允许在分散的各个映射文件中为持久化类设置第二级缓存,还允许在Hibernate的配置文件hibernate.cfg.xml中集中设置第二级缓存,后一种方式更有利于对于缓存相关的配置代码的维护。 
    2.选择合适的缓存插件,每一种缓存插件都有自带的配置文件,需要手动编辑该配置文件。EHCache缓存的配置文件为ehcache.xml,而JBossCache缓存的配置文件为treecache.xml。 

    Hibernate允许在类和集合的粒度上设置第二级缓存。在映射文件中,<class>和<set>元素下都有一个<cache>子元素,这个子元素用来配置第二级缓存。 
    <cache  usage="transactional | read-write| nonstrict-read-write| read-only"   //必须的  指定并发访问策略 
            region="RegionName"   //可选的  指定第二级缓存的区域的名字。默认值为类或集合的名字 
            include="all| non-lazy" />   //可选的  是否加载延迟对象  默认为all 
    <cache>元素的属性 
    name:设置缓存的名字,取值为类的完整名字或者类的集合的名字 
    maxInMemory:设置基于内存的缓存可存放的对象的最大数目 
    eternal:若为true,表示对象永远不会过期,默认为false 
    timeToIdelSeconds:允许对象处于空闲状态的最长时间,以秒为单位。 
    timeToLiveSeconds:允许对象存在于缓存中的最长时间。 
    overflowToDisk:若为true,表示当基于内存的缓存中的对象数目达到了maxInMemory界限,会把溢出的对象写到基于硬盘的缓存中。 

    EHCache适用于Hibernate应用发布在单个机器的场合。若要把应用发布到多台机器中,可以用JBossCache作为Hibernate的第二级缓存。 
    1.在Hibernate配置文件中设置JBossCache适配器,并且为需要使用的第二级缓存的类和集合设置缓存的并发访问策略。 
    2.编辑JBossCache自身的配置文件,名为treecache.xml。这个文件必须存放于应用的classpath中。对于集群环境中的每个节点,都必须提供单独的 

    treecache.xml文件。 

    SessionFactory的evict()方法用于清除对象的散装数据,SessionFactory的getStatistics()方法用于查看第二级缓存中的数据: 
    Map cacheEntries = sessionFactory.getStatistics().getSecondLevelCacheStatistics(regionName).getEntries(); 

    Session与第二级缓存交互有5种模式,分别用org.hibernate.CacheMode类的5个静态常量来表示: 
    CacheMode.NORMAL:正常模式(默认),Session会从第二级缓存中读取数据,也会向其中写入数据 
    CacheMode.IGNORAL:忽略模式,Session不会从第二级缓存中读取数据,也不会向其中写入数据 
    CacheMode.GET:读取模式,Session会从第二级缓存中读取数据,但不会向其中写入数据 
    CacheMode.PUT:写入模式,Session不会从第二级缓存中读取数据,但会向其中写入数据 
    CacheMode.REFRESH:刷新模式,Session不会从第二级缓存中读取数据,但会向其中写入数据。与PUT的区别是:REFRESH会忽略Hibernate配置文件中的 

    hibernate.cache.use_minimal_puts属性,强制刷新第二级缓存中的所有数据。 

    Hibernate提供了3种管理Session对象的方法: 
    1.Session对象的生命周期与本地线程绑定 
    2.Session对象的生命周期与JTA事务绑定 
    3.Hibernate委托程序管理Session对象的生命周期 

    在Hibernate的配置文件中,hibernate.current_session_context_class属性用于指定Session管理方式,可选值包括:thread:Session对象的生命周期与本地线程绑定;jta:Session的生命周期与JTA事务绑定;managed:Hibernate委托程序来管理Session对象的生命周期。 

    Hibernate按照以下规则把Session与本地线程绑定: 
    当一个线程A第一次调用SessionFactory对象的getCurrentSession()方法时,该方法会创建一个新的Session对象,把它与线程A绑定,并将SessionA对象返回。 
    接下来,当线程A再次调用SessionFactory对象的getCurrentSession()方法时,该方法始终返回SessionA对象。 
    当线程A提交与SessionA对象关联的事务时,Hibernate会自动清理SessionA对象的缓存,然后在提交事务后,关闭SessionA对象。此外,若当线程A撤销与SessionA对象关联的事务时,也会自动关闭SessionA对象。 
    若线程A再次调用SessionFactory对象的getCurrentSession()方法时,该方法又会创建一个新的Session对象,把它与线程A绑定。 

    Hibernate按照以下规则把Session与JTA绑定: 
    程序先通过UserTransaction接口声明开始一个JTA事务。接下来当程序第一次调用SessionFactory对象的getCurrentSession()方法时,该方法会创建一个新的Session对象,把它与当前的JTA事务绑定,并将SessionA对象返回。 
    接下来,当程序多次调用SessionFactory对象的getCurrentSession()方法时,该方法始终返回与当前JTA事务绑定的SessionA对象。 
    当程序提交当前JTA事务时,Hibernate会自动清理SessionA对象的缓存,然后在事务提交后,关闭SessionA对象。此外,若当程序撤销当前JTA事务时,也会自动关闭SessionA对象。 

    Hibernate提供两种实现对话的方式: 
    使用游离对象:一个对话包括多个短事务,并且每个短事务对应一个Session对象。事务之间通过游离对象传递业务数据 
    使用手工清理缓存模式下的Session对象:一个对话包括多个短事务,并且整个对话对应一个Session对象 

    采用手工清理缓存模式下的Session,整个对话由多个短事务构成,并且整个对话对应一个Session对象,这个Session对象的生命周期由程序自主管理。程序处理的主要流程如下: 
    创建完Session对象后,立即调用session.setFlushMode(FlushMode.MANUAL)方法,把缓存模式设为手工清理模式。 
    在手工清理模式下,当程序声明提交事务时,Hibernate不会自动清理缓存,因此不会同步更新数据库,不过,Hibernate会自动释放Session对象占用的数据库连接。 
    当程序声明开始事务时,假如当前Session对象不占用数据库连接,Hibernate会自动为它分配数据库连接 
    只有当对话块结束,在提交最后一个事务之前,程序需要调用session.flush()方法手工清理缓存,根据缓存中对象的变化去同步更新数据库。 

    在手工清理Session缓存的模式下,至哟当程序调用Session的flush()方法时才会清理缓存。但通过Session的save()方法执行插入操作时,若对象标识符OID生成策略为identity或select,那么save()方法会立即向数据库插入数据,然后生成对象标识符。 

    Hibernate委托程序来管理Session: 
    把Hibernate配置文件的hibernate.current_session_context_class属性设为managed。 
    当程序创建Session对象后或声明开始一个事务前,调用org.hibernate.context.ManagedContext类的bind()方法,该方法把Session对象与当前线程绑定。 
    在一个事务中,程序可通过SessionFactory的getCurrentSession()方法来获得当前Session对象。 
    当程序提交对话中的一个事务之前,调用org.hibernate.context.ManagedSessionContext类的unbind()方法,该方法解除当前Session对象与当前线程的绑定。 

    org.hibernate.context.ManagedSessionContext类提供了一下静态方法: 
    bind(Session session):把Session和当前线程绑定 
    unbind(SessionFactory factory):解除Session对象与当前的绑定 
    hasBind(SessionFactory factory):判断是否存在与当前线程绑定的Session对象。 

  • 相关阅读:
    eventbus3-intellij-plugin插件搜不到
    flutter控件之CheckBox
    Java中常见数据结构:list与map -底层如何实现
    flutter控件之RadioButton
    git add Untracked files
    执行git push出现"Everything up-to-date"
    用flutter写一个精美的登录页面
    Android Studio最全插件整理
    Mac下git的环境搭建和基本使用
    上周热点回顾(7.1-7.7)团队
  • 原文地址:https://www.cnblogs.com/forerver-elf/p/4724294.html
Copyright © 2020-2023  润新知