iis服务器助手广告广告
返回顶部
首页 > 资讯 > 精选 >NHibernate缓存管理机制怎么理解
  • 711
分享到

NHibernate缓存管理机制怎么理解

2023-06-17 18:06:30 711人浏览 薄情痞子
摘要

这篇文章主要介绍“NHibernate缓存管理机制怎么理解”,在日常操作中,相信很多人在NHibernate缓存管理机制怎么理解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”NHibernate缓存管理机制怎

这篇文章主要介绍“NHibernate缓存管理机制怎么理解”,在日常操作中,相信很多人在NHibernate缓存管理机制怎么理解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”NHibernate缓存管理机制怎么理解”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!

缓存管理面临的主要问题

缓存作为一个数据中心,具备添加、更新、删除数据的操作,因此跟数据库类似,会存在事务性、并发情况下数据一致性等问题需要解决

使用缓存比较典型的方式如下面代码:

Database db = new Database();  Transaction tx = db.BeginTransaction();  try {      //从缓存读取      MyEntity1 entity1 = cache.Get("pk of entity1");       //缓存中没有时从数据库读取      if (entity1 == null) entity1 = db.Get("pk of entity1");            //对entity1进行处理       updated = db.Update(entity1); //entity1的更新保存到数据库中      if (updated) cache.Put(entity1); //数据库更新成功,则更新缓存       //事务中的其他处理       tx.Commit();  }  catch {      tx.Rollback();      throw;  }

上面的示例代码,是在一个事务性环境中使用缓存,存在更新操作(非只读缓存),如果这是一个共享缓存,这样的使用方式存在很多问题,比如说: 如果事务中的其他处理导致异常,数据库中对entity1的更新可以被回滚掉,但是cache中的entity1已经被更新了,如果不处理这样的情况后续从cache中读出的entity1就是一个不正确的数据

所以,要正确的使用缓存,必须有一个完善的方案,充分考虑事务、并发等状况,确保数据的正确性、一致性

NHibernate 2个级别的缓存机制

NHibernate缓存管理机制怎么理解

相对于session来说,一级缓存是私有缓存,二级缓存是共享缓存

session加载实体的搜索顺序为: 1. 从一级缓存中查找;2. 从二级缓存中查找;3. 从数据库查找

一级缓存在事务之间担当了一个隔离区域的作用,事务内对实体对象的所有新增、修改、删除,在事务提交之前对其他session是不可见的,事务提交成功之后批量的将这些更新应用到二级缓存中

这样的2级缓存机制能够在很大程度上确保数据的正确性(比如前面示例代码中事务失败的情况下,就不会将数据更新到二级缓存中,防止了二级缓存出现错误的数据),以及防止ReadUncommited等其他一些事务一致性问题

内部实现上,对一级缓存的管理很简单,所有已加载的实体(以及已经创建proxy但未加载的实体等)都被缓存在持久化上下文(NHibernate.Engine.StatefulPersistenceContext)中

待新增、更新、删除的实体,使用3个列表缓存起来,事务提交的时候将他们应用到数据库和二级缓存中(Flush调用或者因为查询等导致的 NHibernate自动执行的Flush操作也会将他们应用到数据库,但不会应用到二级缓存中,二级缓存只在事务提交成功之后才更新)

NH1.2中这3个列表维护在SessionImpl中,NH2.0以后添加的新功能特性以及代码本身的重构动作相当多,这3个列表维护在NHibernate.Engine.ActionQueue中

二级缓存因为是共享缓存,存在并发更新冲突,但又必须保证二级缓存数据的正确性,因此处理机制就复杂得多。下面是详细的二级缓存处理机制

二级缓存的主要结构

主要接口:

NHibernate缓存管理机制怎么理解

接口职责:

ICache: 统一的缓存存取访问接口

ICacheProvider: 工厂类、初始化类,用于创建ICache对象,启动时对cache server或组件进行初始化,退出时对cache server或组件进行必要的退出处理等

处理过程:

配置文件中指定ICacheProvider的实现类

SessionFactory启动时创建ICacheProvider对象,执行ICacheProvider.Start()方法,并为每一个cache region创建一个ICache对象

整个运行过程中,NHibernate可以使用SessionFactory创建的ICache完成缓存的存取操作

SessionFactory关闭时调用ICacheProvider.Stop()方法

实体状态的转换:

NHibernate缓存管理机制怎么理解

以memcached为例,实体缓存时的状态转换如上图

  • NHibernate2.1新特性之Tuplizers

  • 浅析NHibernate一对一映射的延迟加载

  • LINQ to sql与NHibernate横向对比

  • 讲解Nhibernate与代码生成

  • 讲解NHibernate Session

CacheEntry表示一个需要存储到缓存中或者从缓存中返回的对象

CacheEntry中包含拆解后的实体属性值(DisassembledState,object[]类型,数组中是每个属性的值)、实体的版本(乐观时使用)、类型名称。采用这样的处理方式,我们定义的domain对象就不需要实现Serializable接口,也可以被序列化存储到缓存中

对于primitive type的实体属性,拆解和组装过程没有特殊的处理;对于composite component、one-to-one、one-to-many的collection等实体属性,分解之后在DisassembledState中存放的是owner(即当前被缓存的实体对象)的id值,组装过程中根据这个id值去取相关的对象设置到这个属性上(可能从一级缓存、二级缓存,或者数据库加载,依赖于具体的设置和运行时的状态)

CacheItem用于解决并发更新二级缓存时的数据一致性问题(不考虑这个问题的话,直接将CacheEntry存到缓存中就可以了),主要是对soft lock机制的处理,后面详细介绍

将CacheItem转换成DictionaryEntry的处理,是由NHibernate.Caches.Memcache进行的,完全是一个多余的处理

NHibernate使用规则 [完整的类名#id值] 生成cache key,NHibernate.Caches.Memcache会在NHibernate生成的key前面再添加上 [region名称@](如果类的hbm文件中没有设置region名称,默认region为完整的类名,这样完整类名会在cache key中出现2次)

memcached的key最长只能是250个字符,NHibernate.Caches.Memcache在cache key超过250字符时,取key的hash值作为新的memcached key值,因为这样会存在hash冲突,所以NHibernate.Caches.Memcache构造一个DictionaryEntry对象(原 key值的MD5作为DictionaryEntry的key值,被缓存的对象作为value),将 DictionaryEntry存到memcached中。从缓存get对象时,NHibernate.Caches.Memcache对返回的 DictionaryEntry的key值再做一次比较,排除掉hash冲突的情况

这样的方式使用memcached,效率上太浪费了。一不留神,完整的类名就会在缓存数据中出现4次!

基于NHibernate的机制和memcached的特点,可以考虑使用cache region来区分不同的memcached集群,比如说用A、B 2台服务器作为只读缓存,region取名为readonly_region;C、D、E 3台服务器作为读写缓存,region取名为readwrite_region

从DictionaryEntry到Memcached Server这段处理由Memcached.ClientLibrary完成,关于Memcached.ClientLibrary的分析,参考memcached client - memcacheddotnet (Memcached.ClientLibrary)

解决并发更新冲突

NHibernate定义了3中缓存策略: 只读策略(useage="read-only")、非严格的读写策略(useage="nonstrict-read-write")和读写策略(useage="read-write")

处理并发更新的结构

NHibernate缓存管理机制怎么理解

ICacheConcurrencyStrategy聚合了一个ICache对象,NHibernate操作缓存时不是直接使用ICache对象,而是通过ICacheConcurrencyStrategy 完成,这样确保系统对二级缓存的操作,都是在特定的缓存策略下进行的

ICacheConcurrencyStrategy和ICache接口的语义有差别,ICache纯粹是缓存的操作接口,而ICacheConcurrencyStrategy则与实体的状态变化相关

ICacheConcurrencyStrategy的语义

Evict: 让缓存项失效

Get, Put, Remove, Clear: 与ICache的相关方法相同,纯粹的缓存读取、存储等操作

Insert, AfterInsert: 新增实体时的方法,实体新增到数据库之后会执行Insert方法,事务提交后会执行AfterInsert方法。这些方法中如何处理二级缓存,由具体的缓存策略确定

Update, AfterUpdate: 更新实体时的方法,实体修改update到数据库之后会执行Update方法,事务提交后会执行AfterUpdate方法。这些方法中如何处理二级缓存,由具体的缓存策略确定

Lock, Release: 这2个方法分别对缓存项进行加锁、解锁。语义上,事务中开始更新实体时对缓存项执行Lock方法,事务提交后对缓存项执行Release方法,在这些方法中如何处理二级缓存由具体的缓存策略确定

在前面实体状态转换的图中,CacheEntry到CacheItem的转换由ICacheConcurrencyStrategy接口完成,CacheItem只被ICacheConcurrencyStrategy使用,NHibernate内部其他需要与缓存交互的地方均使用 CacheEntry和ICacheConcurrencyStrategy接口

ReadOnly策略

运用场景为,数据不会被更新,NHibernate不更新二级缓存的数据。采用只读策略的实体不能执行update操作,否则会抛出异常,可以执行新增、删除操作。只读策略只在实体从数据库加载后写到缓存中

UnstrictReadWrite策略

运用场景为,数据会被更新,但频率不高,并发存储情况很少

采用该策略的实体,新增时不会操作二级缓存;更新时只是简单的将二级缓存的数据删除掉(Update, AfterUpdate方法中都会删除二级缓存数据),这样期间或者后续的请求将从数据库加载数据并重新缓存

因为更新过程没有对缓存数据使用lock,读取时也不会进行版本检查,因此并发存取时无法保证数据的一致性,下面是一个这样的示例场景:

NHibernate缓存管理机制怎么理解

1, 2: 请求1在事务中执行更新,NH更新数据库并从二级缓存删除该数据

某些操作(例如ISession.Evict)导致请求1的一级缓存中该数据失效

4, 5: 请求2从数据库加载该数据,并放入二级缓存。因为请求2在另外的事务上下文中,因此加载的数据不包含请求1的更新

请求1需要重新加载该数据,因为一级缓存中没有,因此从二级缓存读取,结果读到的将是一份错误的数据

ReadWrite策略

运用场景为,数据可能经常并发更新,NHibernate确保ReadCommitted的事务隔离级别,如果数据库的隔离级别为RepeatableRead,该策略也能基本保证二级缓存满足RepeatableRead的隔离级别

NHibernate通过使用版本、timestamp检查、soft lock等机制实现这一目标

soft lock的原理比较简单,假如事务中需要更新key为839的数据,首先创建一个soft lock对象,用839这个key存到cache中(如果cache中原来已经用839的key缓存了这个数据,也直接用soft lock覆盖他),然后更新数据库,完成事务的其他处理,事务提交之后将id为839的实体对象再重新存入cache中。事务期间其他所有从二级缓存读取 839的请求都将返回soft lock对象,表明二级缓存中这个数据已经被加锁了,因此转向数据库读取

NHibernate缓存管理机制怎么理解

ReadWriteCache.ILockable为soft lock接口,CacheItem和CacheLock两个类实现了这个接口

更新数据时的处理步骤

NHibernate缓存管理机制怎么理解

更新操作前先锁定二级缓存的数据

2,3: 从二级缓存取数据,如果返回的是null或者CacheItem,则新建一个CacheLock并存入二级缓存;如果返回的是一个CacheLock,则表明有另外的事务已经锁定该值,将并发锁定计数器增1并更新回二级缓存中

返回lock对象给EntityAction

5, 6, 7: 更新数据库,完成事务的其他处理,提交事务。ReadWriteCache的Update不做任何处理

事务提交后执行ReadWriteCache的AfterUpdate方法

先从二级缓存读取CacheLock对象,如果返回null说明锁已经过期(事务时间太长造成)

如果锁已经过期,或者返回的CacheLock已经不是加锁时返回的那个(锁过期后又被其他线程重新加锁了),则新建一个CacheLock,设为 unlock状态放回二级缓存,结束整个更新处理

如果CacheLock为并发锁状态,则将CacheLock并发锁计数器减一,更新回二级缓存,结束整个更新处理

如果不是上面这些情况,则说明期间没有并发更新,将新的实体状态更新到二级缓存(锁自然被解除掉了)

一旦发生并发更新,并发的***一个事务提交之后,NHibernate也不会将实体重新存入二级缓存,此时在二级缓存中存储的是一个unlock状态的 CacheLock对象,在这个CacheLock过期以后,实体才可能被重新缓存到二级缓存中。采用这样的处理方式,是因为并发事务发生时,NHibernate不知道数据库中哪一个事务先执行、哪一个后执行,为了确保ReadWrite策略的语义,强制这段时间内二级缓存失效

ReadWriteCache的Get方法,除了在二级缓存的数据被锁定时将返回null之外,还会将缓存项的时间戳与请求线程的事务时间进行比较,也可能返回null,使得请求转向数据库查询,由数据库保证事务隔离级别

而put方法还会比较实体的版本(使用乐观锁的情况)

看源代码时,Timestamper类是一个时间戳与计数器结合的产物,在时间上精确到毫秒,每毫秒内采用1-4096的一个计数器,增量分配。NHibernate.Caches.MemCache将ReadWriteCache的二级缓存锁超时时间设置为0xea60000,换算过来就是1分钟

到此,关于“NHibernate缓存管理机制怎么理解”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注编程网网站,小编会继续努力为大家带来更多实用的文章!

--结束END--

本文标题: NHibernate缓存管理机制怎么理解

本文链接: https://www.lsjlt.com/news/291701.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • NHibernate缓存管理机制怎么理解
    这篇文章主要介绍“NHibernate缓存管理机制怎么理解”,在日常操作中,相信很多人在NHibernate缓存管理机制怎么理解问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”NHibernate缓存管理机制怎...
    99+
    2023-06-17
  • WCF缓存机制怎么理解
    这篇文章主要讲解了“WCF缓存机制怎么理解”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“WCF缓存机制怎么理解”吧!缓存是很占内存的,缓存也有它的好处,这里就WCF缓存机制分析一个案例,希望...
    99+
    2023-06-17
  • redis缓存清理机制
    redis 缓存清理机制通过采取淘汰策略、内存溢出策略和手动淘汰来释放空间,以便容纳新数据。常用的淘汰策略包括 lru、lfu、fifo;内存溢出策略包括 volatile-lru、vo...
    99+
    2024-04-20
    redis
  • redis清理缓存机制
    redis 提供了多种清理缓存机制,包括:定期过期策略 (ttl):为键设置生存时间,到期后自动删除。最近最少使用 (lru) 算法:删除最近最少使用的键,优先保留最近使用的键。定期清理...
    99+
    2024-04-20
    redis 键值对
  • 怎么理解Flutter图片加载与缓存机制
    本篇内容主要讲解“怎么理解Flutter图片加载与缓存机制”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“怎么理解Flutter图片加载与缓存机制”吧!前言今天来学习一下 Flutter 自身是如...
    99+
    2023-06-25
  • golang内存管理机制解析
    go语言采用垃圾回收机制自动管理内存,防止泄漏。内存划分为栈(局部变量)、堆(动态数据)、静态数据和mmap区。垃圾回收器检测并释放不再被引用的对象内存,包括标记阶段和清除阶段。实战案例...
    99+
    2024-04-23
    golang 内存管理 go语言 垃圾回收器
  • HTTP缓存机制的原理
    这篇文章主要介绍“HTTP缓存机制的原理”,在日常操作中,相信很多人在HTTP缓存机制的原理问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”HTTP缓存机制的原理”的疑惑有所帮...
    99+
    2024-04-02
  • Hibernate缓存机制的原理
    本篇内容主要讲解“Hibernate缓存机制的原理”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Hibernate缓存机制的原理”吧!1. 为什么要用 Hibe...
    99+
    2024-04-02
  • 带你深入理解MyBatis缓存机制
    目录一、简介1、缓存机制介绍2. 一级缓存和二级缓存二、一级缓存三、二级缓存3.1 mybatis自带的二级缓存3.1.1 代码测试二级缓存3.1.2 查询结果存入二级缓存的时机3....
    99+
    2024-04-02
  • redis缓存存储Session原理机制
    目录基于 Redis 存储 Session首先安装 redis 存储引擎的包设置session过期时间分布式获取Session:(redis)基于 Redis 存储 Session ...
    99+
    2024-04-02
  • Python内存管理机制
    1 概述对于Python这样的动态语言,如何高效的管理内存,是很重要的一部分,在很大程度上决定了Python的执行效率。与大多数编程语言不同,Python中的变量无需事先申明,变量无需指定类型,程序员无需关心内存管理,Python解释器给你...
    99+
    2023-01-31
    管理机制 内存 Python
  • redis缓存存储Session原理机制是什么
    这篇文章主要讲解了“redis缓存存储Session原理机制是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“redis缓存存储Session原理机制是什么”吧!基于 Redis 存储 S...
    99+
    2023-06-25
  • go内存管理机制是什么
    Go语言的内存管理机制是基于垃圾回收(Garbage Collection)的。 Go语言中的内存管理是由垃圾回收器负责的,它会自动...
    99+
    2023-10-27
    go
  • android内存管理机制是什么
    Android的内存管理机制是一种动态的机制,主要包括以下几个方面:1. 内存分配:Android使用堆来分配内存。堆是一个运行时数...
    99+
    2023-09-13
    android
  • unity内存管理机制是什么
    Unity的内存管理机制是自动化管理的。Unity使用了一种称为垃圾回收(Garbage Collection)的技术来自动管理和释...
    99+
    2023-10-27
    unity
  • CLR内存管理机制是什么
    这篇文章主要介绍“CLR内存管理机制是什么”,在日常操作中,相信很多人在CLR内存管理机制是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”CLR内存管理机制是什么”的疑惑有所帮助!接下来,请跟着小编一起来...
    99+
    2023-06-17
  • python内存管理机制是什么
    Python内存管理机制是自动化的。Python使用引用计数来跟踪和回收对象的内存。每个对象都有一个引用计数,当引用计数减少到0时,...
    99+
    2023-08-31
    python
  • 深入理解MySQL中MVCC与BufferPool缓存机制
    目录一、MVCC机制undo日志版本链与read-view机制版本链比对规则二、BufferPool机制三、总结一、MVCC机制 MVCC(Multi Version Concurr...
    99+
    2024-04-02
  • shiro中缓存机制的原理是什么
    本篇文章给大家分享的是有关shiro中缓存机制的原理是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。Shiro提供了类似于Spring的Cache抽象,即Shiro本身不实...
    99+
    2023-05-31
    shiro
  • Python内存管理机制的原理是什么
    今天就跟大家聊聊有关Python内存管理机制的原理是什么,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。小块空间的内存池在Python中,许多时候申请的内存都是小块的内存,这些小块内存...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作