2024年10月hibernate一级缓存(Mybatis的缓存讲解)

 更新时间:2024-10-12

  ⑴hibernate一级缓存(Mybatis的缓存讲解

  ⑵Mybatis的缓存讲解

  ⑶前段时间阿粉的一个朋友和阿粉吃饭,在吃饭的时候和阿粉疯狂的吐槽面试官,说面试官问的问题都是些什么问题呀,我一个干了三四年的开发,也不说问点靠谱的,阿粉很好奇,问题问完基础的,一般不都是根据你自己的简历进行提问么?而接下来他说的出来的问题,阿粉表示,阿粉需要继续学习了。说到这个,读者大人们肯定心想,阿粉是在开玩笑么?你一个Java程序员,你不知道Mybatis是啥么?不就是个持久层的框架么,这东西有啥好说的呢?但是阿粉还是要给大家说。为什么说Mybatis是一个半自动ORM的框架呢?ORM,是Object和Relation之间的映射,而Mybatis在查询关联对象或关联集合对象时,需要手动编写sql来完成,所以,称之为半自动ORM框架,而Hibernate属于全自动ORM映射工具,使用Hibernate查询关联对象或者关联集合对象时,可以根据对象关系模型直接获取,所以它是全自动的。这也是为什么有些面试官在面试初级程序员的时候,很喜欢说,你觉得Mybatis,和Hibernate都有什么优缺点,为啥你们选择使用的Mybatis而不选择使用Hibernate呢?我们都说了Mybatis是什么了,接下来肯定需要说说面试官都问了什么问题,能让阿粉的朋友变得非常犹豫。当我们面试的时候,说完这个,一般情况下,面试官一定会追问下去,毕竟技术就是要问到你的知识盲区才会停止。那我们就来画个图表示一下一级缓存那面试官肯定会说,直接从数据库查不就行了,为啥要一级缓存呢?当我们使用MyBatis开启一次和数据库的会话时,MyBatis会创建出一个SqlSession对象表示一次与数据库之间的信息传递,在我们执行SQL语句的过程中,们可能会反复执行完全相同的查询语句,如果不采取一些措施,我们每一次查询都会查询一次数据库,而如果在极短的时间内做了很多次相同的查询操作,那么这些查询返回的结果很可能相同。也就是说,如果我们在短时间内,频繁的去执行一条SQL,查询返回的结果本来应该是改变了,但是我们查询出来的时候,会出现结果一致的情况,正是为了解决这种问题,也为了减轻数据库的开销,所以Mybatis默认开启了一级缓存。Mybatis的二级缓存一般如果你不对他进行设置,他是不会开启的,而二级缓存是什么呢?Mybatis中的二级缓存实际上就是mapper级别的缓存,而这时候肯定会有人说,那么不同之间的Mapper是同一个缓存么?答案是否定的,他不是一个,Mapper级别的缓存实际上就是相同的Mapper使用的是一个二级缓存,但是在二级缓存中,又有多个不同的SqlSession,而不同的Mapper之间的二级缓存也就是互相不会影响的。就类似下面的图这二级缓存是不是就看起来有点意思了?那怎么能够开启二级缓存呢?.MyBatis配置文件.MyBatis要求返回的POJO必须是可序列化的.Mapper的xml配置文件中加入标签既然我们想要了解这个二级缓存,那么必然,我们还得知道它里面的配置都有哪些含义。我们先从标签看起,然后从源码里面看都有哪些配置信息提供给我们使用:blocking:直译就是调度,而在Mybatis中,如果缓存中找不到对应的key,是否会一直blocking,直到有对应的数据进入缓存。eviction:缓存回收策略而缓存回收策略,在源码中是有直接体现的,那么他们分别都对应了什么形式呢?大家虽然看着PERPETUAL排在了第一位,但是它可不是默认的,在Mybatis的缓存策略里面,默认的是LRU。PERPETUAL:源代码如下:恩?看着是不是有点眼熟,它怎么就只是包装了HashMap?你还别奇怪,他还真的就是使用的HashMap,不得不说,虽然人家是使用的HashMap,但是那可是比咱们写的高端多了。既然使用HashMap,那么必然就会有Key,那么他们的Key是怎么设计的?CacheKey:确实牛逼,至于内部如何初始化,如何进行操作,大家有兴趣的可以去阅读一下源码,导入个源码包,打开自己看一下。FIFO:先进先出缓冲淘汰策略在FIFO淘汰策略中使用了Java中的Deque,而Deque一种常用的数据结构,可以将队列看做是一种特殊的线性表,该结构遵循的先进先出原则。Java中,LinkedList实现了Queue接口,因为LinkedList进行插入、删除操作效率较高。当你看完这个源码的时候,是不是就感觉源码其实也没有那么难看懂,里面都是我们已经掌握好的知识,只不过中间做了一些操作,进行了一些封装。LRU:最近最少使用的缓存策略而LUR算法,阿粉之前都说过,如果对这个算法感兴趣的话,文章地址给大家送上,经典的LRU算法,你真的了解吗?而我们需要看的源码则是在Mybatis中的源码,SOFT:基于垃圾回收器状态和软引用规则的对象在看到基于垃圾回收器的时候,阿粉就已经开始兴奋了,竟然有GC的事情,那还不赶紧看看,这如此高大上(装杯)的事情,来瞅瞅吧!WEAK:基于垃圾收集器状态和弱引用规则的对象WeakCache在实现上与SoftCache几乎相同,只是把引用对象由SoftReference软引用换成了WeakReference弱引用。在这里阿粉也就不再多说了,关于Mybatis的二级缓存,你了解了么?下次遇到面试官问这个的时候,你应该知道怎么成功(装杯不被打了吧。

  ⑷hibarnate和mybatis的区别

  ⑸开发对比开发速度Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。要用好Mybatis还是首先要先理解好Hibernate。开发社区Hibernate与Mybatis都是流行的持久层开发框架,但Hibernate开发社区相对多热闹些,支持的工具也多,更新也快,当前最高版本..。而Mybatis相对平静,工具较少,当前最高版本.。开发工作量Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。、系统调优对比Hibernate的调优方案制定合理的缓存策略;尽量使用延迟加载特性;采用合理的Session管理机制;使用批量抓取,设定合理的批处理参数(batch_size;进行合理的O/R映射设计Mybatis调优方案MyBatis在Session方面和Hibernate的Session生命周期是一致的,同样需要合理的Session管理机制。MyBatis同样具有二级缓存机制。MyBatis可以进行详细的SQL优化设计。SQL优化方面Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。HibernateHQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Logj进行日志记录。扩展性方面Hibernate与具体数据库的关联只需在XML文件中配置即可,所有的HQL语句与具体使用的数据库无关,移植性很好。MyBatis项目中所有的SQL语句都是依赖所用的数据库的,所以不同数据库类型的支持不好。、对象管理与抓取策略对象管理Hibernate是完整的对象/关系映射解决方案,它提供了对象状态管理(statemanagement的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的JDBC/SQL持久层方案中需要管理SQL语句,Hibernate采用了更自然的面向对象的视角来持久化Java应用中的数据。换句话说,使用Hibernate的开发者应该总是关注对象的状态(state,不必考虑SQL语句的执行。这部分细节已经由Hibernate掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。抓取策略Hibernate对实体关联对象的抓取有着良好的机制。对于每一个关联关系都可以详细地设置是否延迟加载,并且提供关联抓取、查询抓取、子查询抓取、批量抓取四种模式。它是详细配置和处理的。而Mybatis的延迟加载是全局配置的。、缓存机制对比Hibernate缓存Hibernate一级缓存是Session缓存,利用好一级缓存就需要对Session的生命周期进行管理好。建议在一个Action操作中使用一个Session。一级缓存需要对Session进行严格管理。Hibernate二级缓存是SessionFactory级的缓存。SessionFactory的缓存分为内置缓存和外置缓存。内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定SQL语句等),对于应用程序来说,它是只读的。外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它可以被所有session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。、优势对比Mybatis优势MyBatis可以进行更为细致的SQL优化,可以减少查询字段。MyBatis容易掌握,而Hibernate门槛较高。Hibernate优势Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。

  ⑹Hibernate的二级缓存指的是哪个东西听说一级缓存指的是SESSION

  ⑺二级缓存是sessionFactory级别的缓存。所有session都可以用。

  ⑻Hibernate的缓存技术有哪些

  ⑼缓存是数据库数据在内存中的临时容器,它包含了库表数据在内存中的临时拷贝,位于数据库与应用程序之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高应用的运行性能。Hibernate的缓存机制.持久化层的缓存的范围持久层设计中,往往需要考虑几个不同层次中的数据缓存策略。这些层次的划分标准针对不同情况有所差异,一般而言,ORM的数据缓存应包含如下几个层次:事务级缓存(TransactionLayerCache)缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的对象形式。应用级/进程级缓存(Application/ProcessLayerCache)缓存被进程内的所有事务共享。这些事务有可能是并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。对象的松散数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。集群级缓存(ClusterLayerCache)在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。对大多数应用来说,应该慎重地考虑是否需要使用集群范围的缓存,因为访问的速度不一定会比直接访问数据库数据的速度快多少。持久层提供以上多种层次的缓存。如果在事务级缓存中没有查到相应的数据,还可以到进程级或集群级缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务级缓存是持久化层的第一级缓存,通常它是必需的;进程级或集群级缓存是持久化层的第二级缓存,通常是可选的。.hibernate缓存机制Hibernate提供了两种缓存,第一种是Session的缓存,又称为一级缓存。由于Session对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第一级缓存是必需的,不允许而且事实上也无法卸除。在第一级缓存中,持久化类的每个实例都具有唯一的OID。

  ⑽怎样解决hibernate中一级缓存导致数据不能刷新

  ⑾Hibernate的一级缓存是由Session提供的,因此它只存在于Session的生命周期中,也就是当Session关闭的时候该Session所管理的一级缓存也会立即被清除。Hibernate的一级缓存是Session所内置的,不能被卸载,也不能进行任何配置。一级缓存采用的是key-value的Map方式来实现的,在缓存实体对象时,对象的主关键字ID是Map的key,实体对象就是对应的值。所以说,一级缓存是以实体对象为单位进行存储的,在访问的时候使用的是主关键字ID。虽然,Hibernate对一级缓存使用的是自动维护的功能,没有提供任何配置功能,但是可以通过Session中所提供的方法来对一级缓存的管理进行手工干预。Session中所提供的干预方法包括以下两种。evict():用于将某个对象从Session的一级缓存中清除。clear():用于将一级缓存中的对象全部清除。在进行大批量数据一次性更新的时候,会占用非常多的内存来缓存被更新的对象。这时就应该阶段性地调用clear()方法来清空一级缓存中的对象,控制一级缓存的大小,以避免产生内存溢出的情况。

  ⑿hiberesmybatis哪个好

  ⒀各有各的好处,.Hibernate简介Hibernate对数据库结构提供了较为完整的封装,Hibernate的O/RMapping实现了POJO和数据库表之间的映射,以及SQL的自动生成和执行。程序员往往只需定义好了POJO到数据库表的映射关系,即可通过Hibernate提供的方法完成持久层操作。程序员甚至不需要对SQL的熟练掌握,Hibernate/OJB会根据制定的存储逻辑,自动生成对应的SQL并调用JDBC接口加以执行。.MyBatis简介iBATIS的着力点,则在于POJO与SQL之间的映射关系。然后通过映射配置文件,将SQL所需的参数,以及返回的结果字段映射到指定POJO。相对Hibernate“O/R”而言,iBATIS是一种“SqlMapping”的ORM实现。第二章开发对比开发速度Hibernate的真正掌握要比Mybatis来得难些。Mybatis框架相对简单很容易上手,但也相对简陋些。个人觉得要用好Mybatis还是首先要先理解好Hibernate。开发社区Hibernate与Mybatis都是流行的持久层开发框架,但Hibernate开发社区相对多热闹些,支持的工具也多,更新也快,当前最高版本..。而Mybatis相对平静,工具较少,当前最高版本.。开发工作量Hibernate和MyBatis都有相应的代码生成工具。可以生成简单基本的DAO层方法。针对高级查询,Mybatis需要手动编写SQL语句,以及ResultMap。而Hibernate有良好的映射机制,开发者无需关心SQL的生成与结果映射,可以更专注于业务流程。第三章系统调优对比Hibernate的调优方案制定合理的缓存策略;尽量使用延迟加载特性;采用合理的Session管理机制;使用批量抓取,设定合理的批处理参数(batch_size;进行合理的O/R映射设计Mybatis调优方案MyBatis在Session方面和Hibernate的Session生命周期是一致的,同样需要合理的Session管理机制。MyBatis同样具有二级缓存机制。MyBatis可以进行详细的SQL优化设计。SQL优化方面Hibernate的查询会将表中的所有字段查询出来,这一点会有性能消耗。Hibernate也可以自己写SQL来指定需要查询的字段,但这样就破坏了Hibernate开发的简洁性。而Mybatis的SQL是手动编写的,所以可以按需求指定查询的字段。HibernateHQL语句的调优需要将SQL打印出来,而Hibernate的SQL被很多人嫌弃因为太丑了。MyBatis的SQL是自己手动写的所以调整方便。但Hibernate具有自己的日志统计。Mybatis本身不带日志统计,使用Logj进行日志记录。扩展性方面Hibernate与具体数据库的关联只需在XML文件中配置即可,所有的HQL语句与具体使用的数据库无关,移植性很好。MyBatis项目中所有的SQL语句都是依赖所用的数据库的,所以不同数据库类型的支持不好。第四章对象管理与抓取策略对象管理Hibernate是完整的对象/关系映射解决方案,它提供了对象状态管理(statemanagement的功能,使开发者不再需要理会底层数据库系统的细节。也就是说,相对于常见的JDBC/SQL持久层方案中需要管理SQL语句,Hibernate采用了更自然的面向对象的视角来持久化Java应用中的数据。换句话说,使用Hibernate的开发者应该总是关注对象的状态(state,不必考虑SQL语句的执行。这部分细节已经由Hibernate掌管妥当,只有开发者在进行系统性能调优的时候才需要进行了解。而MyBatis在这一块没有文档说明,用户需要对对象自己进行详细的管理。抓取策略Hibernate对实体关联对象的抓取有着良好的机制。对于每一个关联关系都可以详细地设置是否延迟加载,并且提供关联抓取、查询抓取、子查询抓取、批量抓取四种模式。它是详细配置和处理的。而Mybatis的延迟加载是全局配置的。第五章缓存机制对比Hibernate缓存Hibernate一级缓存是Session缓存,利用好一级缓存就需要对Session的生命周期进行管理好。建议在一个Action操作中使用一个Session。一级缓存需要对Session进行严格管理。Hibernate二级缓存是SessionFactory级的缓存。SessionFactory的缓存分为内置缓存和外置缓存。内置缓存中存放的是SessionFactory对象的一些集合属性包含的数据(映射元素据及预定SQL语句等),对于应用程序来说,它是只读的。外置缓存中存放的是数据库数据的副本,其作用和一级缓存类似.二级缓存除了以内存作为存储介质外,还可以选用硬盘等外部存储设备。二级缓存称为进程级缓存或SessionFactory级缓存,它可以被所有session共享,它的生命周期伴随着SessionFactory的生命周期存在和消亡。MyBatis缓存MyBatis包含一个非常强大的查询缓存特性,它可以非常方便地配置和定制。MyBatis中的缓存实现的很多改进都已经实现了,使得它更加强大而且易于配置。默认情况下是没有开启缓存的,除了局部的session缓存,可以增强变现而且处理循环依赖也是必须的。要开启二级缓存,你需要在你的SQL映射文件中添加一行:《cache/》字面上看就是这样。这个简单语句的效果如下:映射语句文件中的所有select语句将会被缓存。映射语句文件中的所有insert,update和delete语句会刷新缓存。缓存会使用LeastRecentlyUsed(LRU,最近最少使用的)算法来收回。根据时间表(比如noFlushInterval,没有刷新间隔),缓存不会以任何时间顺序来刷新。缓存会存储列表集合或对象(无论查询方法返回什么)的个引用。缓存会被视为是read/write(可读/可写)的缓存,意味着对象检索不是共享的,而且可以安全地被调用者修改,而不干扰其他调用者或线程所做的潜在修改。所有的这些属性都可以通过缓存元素的属性来修改。比如:《cacheeviction=“FIFO“flushInterval=““size=““readOnly=“true“/》这个更高级的配置创建了一个FIFO缓存,并每隔秒刷新,存数结果对象或列表的个引用,而且返回的对象被认为是只读的,因此在不同线程中的调用者之间修改它们会导致冲突。可用的收回策略有,默认的是LRU:LRU–最近最少使用的:移除最长时间不被使用的对象。FIFO–先进先出:按对象进入缓存的顺序来移除它们。SOFT–软引用:移除基于垃圾回收器状态和软引用规则的对象。WEAK–弱引用:更积极地移除基于垃圾收集器状态和弱引用规则的对象。flushInterval(刷新间隔)可以被设置为任意的正整数,而且它们代表一个合理的毫秒形式的时间段。默认情况是不设置,也就是没有刷新间隔,缓存仅仅调用语句时刷新。size(引用数目)可以被设置为任意正整数,要记住你缓存的对象数目和你运行环境的可用内存资源数目。默认值是。readOnly(只读)属性可以被设置为true或false。只读的缓存会给所有调用者返回缓存对象的相同实例。因此这些对象不能被修改。这提供了很重要的性能优势。可读写的缓存会返回缓存对象的拷贝(通过序列化)。这会慢一些,但是安全,因此默认是false。相同点Hibernate和Mybatis的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。不同点Hibernate的二级缓存配置在SessionFactory生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置是那种缓存。MyBatis的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且Mybatis可以在命名空间中共享相同的缓存配置和实例,通过Cache-ref来实现。两者比较因为Hibernate对查询对象有着良好的管理机制,用户无需关心SQL。所以在使用二级缓存时如果出现脏数据,系统会报出错误并提示。而MyBatis在这一方面,使用二级缓存时需要特别小心。如果不能完全确定数据更新操作的波及范围,避免Cache的盲目使用。否则,脏数据的出现会给系统的正常运行带来很大的隐患。第六章Hibernate与Mybatis对比总结两者相同点Hibernate与MyBatis都可以是通过SessionFactoryBuider由XML配置文件生成SessionFactory,然后由SessionFactory生成Session,最后由Session来开启执行事务和SQL语句。其中SessionFactoryBuider,SessionFactory,Session的生命周期都是差不多的。Hibernate和MyBatis都支持JDBC和JTA事务处理。Mybatis优势MyBatis可以进行更为细致的SQL优化,可以减少查询字段。MyBatis容易掌握,而Hibernate门槛较高。Hibernate优势Hibernate的DAO层开发比MyBatis简单,Mybatis需要维护SQL和结果映射。Hibernate对对象的维护和缓存要比MyBatis好,对增删改查的对象的维护要方便。Hibernate数据库移植性很好,MyBatis的数据库移植性不好,不同的数据库需要写不同SQL。Hibernate有更好的二级缓存机制,可以使用第三方缓存。MyBatis本身提供的缓存机制不佳。他人总结Hibernate功能强大,数据库无关性好,O/R映射能力强,如果你对Hibernate相当精通,而且对Hibernate进行了适当的封装,那么你的项目整个持久层代码会相当简单,需要写的代码很少,开发速度很快,非常爽。Hibernate的缺点就是学习门槛不低,要精通门槛更高,而且怎么设计O/R映射,在性能和对象模型之间如何权衡取得平衡,以及怎样用好Hibernate方面需要你的经验和能力都很强才行。iBATIS入门简单,即学即用,提供了数据库查询的自动对象绑定功能,而且延续了很好的SQL使用经验,对于没有那么高的对象模型要求的项目来说,相当完美。iBATIS的缺点就是框架还是比较简陋,功能尚有缺失,虽然简化了数据绑定代码,但是整个底层数据库查询实际还是要自己写的,工作量也比较大,而且不太容易适应快速数据库修改。

  ⒁为什么要使用hibernate

  ⒂说说我们的选择吧原因有:.我们是做平台的,客户要求多种多样,我们是需要支持多个数据库的,Hibernate可以比较容易屏蔽数据库的差异;.Hibernate采用面向对象的方式来写SQL,也就是HQL和Criteria,在数据库和Dao之间多了一层,数据库的改动可以通过映射关系屏蔽部分影响。.因为我们是要不断的增加功能,偶然要做做系统重构,快速快发尤其重要,Hibernate的代码量和改动量都要比其他框架来的少,起码经过我们的封装已经使得用起来是很简单了。.对于性能有影响的地方和很难用Hibernate表达的地方我们会采用JdbcTemplate,或者采用View封装一次再map到Hibernate,采用Hibernate也不排斥其他持久层框架的存在。.尽量少用Oomany,Manytoone等功能,可能这里不太OO,但是代码明了,不容易出问题。.我们暂时还没有遇到几千万的数据量那么大的客户,要做到那么大数据量的时候也可以从数据库,系统,网络各个方面来优化。系统推到重来也不是什么问题。.Hibernate的一级缓存对于长Transaction的业务复杂的代码反而有好处,见上面的某些分析。.采用缓存和静态页面可以消除部分性能影响,或者采用数据库特有功能,不过取消Hibernate的二级缓存,采用Spring的缓存或者自己搞缓存。.文档多,容易解决问题,也是JPA标准的重要参考。Hibernate不好的地方:.多占内存,因为他需要把domain对应的configuration都load到内存里面去,多用内存是正常的,但是出现OutofMemerey肯定不是Hibernate的问题了,一般应用内存还是够的。.性能问题。Hibernate或者Ibatis也好,最终都是通过反射把ResultSet变为对应的DomainObject,跟了一下Hibernate的内部代码,好像是用Method.invoke来调用get和set方法的,用了Cglib或者动态代理方式,这个方式肯定是要比直接调用get和set方法要慢的。在JDK不断优化的今天,这个差距应该会缩小。但是Ibatais应该也是通过这个方式来做,没有看过不太肯定。Hibernate多了一个将HQL或者DomainObject转化为SQL的过程,这个过程也会消耗一些性能,例如字符串拼接,记录DomainObject的关系等。经过以上分析,可能Hibernate会给我带来一定的性能损失,但是我可以通过其他办法来弥补,内存就更不是问题了。但是他确实带来了比较好的地方,因此我们会继续用Hibernate。所以说Hibernate适合做企业级应用,对于那种内存和性能要求都很高或者本来就用Ibatis的情况,其实可以选择Ibatias或者JdbcTemplate的。就性能而言,JdbcTemplate》Ibatis《Hibernate除了缓存的作用外只说DB操作,纯JDBC是最快的,因为那样没有任何负担,但是代码搞得很难看,你会这么选择吗?

  ⒃hibernate缓存的详细配置

  ⒄很多人对二级缓存都不太了解,或者是有错误的认识,我一直想写一篇文章介绍一下hibernate的二级缓存的,今天终于忍不住了。我的经验主要来自hibernate.版本,基本原理和.、.是一样的,请原谅我的顽固不化。hibernate的session提供了一级缓存,每个session,对同一个id进行两次load,不会发送两条sql给数据库,但是session关闭的时候,一级缓存就失效了。二级缓存是SessionFactory级别的全局缓存,它底下可以使用不同的缓存类库,比如ehcache、oscache等,需要设置hibernate.cache.provider_class,我们这里用ehcache,在.中就是hibernate.cache.provider_class=.sf.hibernate.cache.EhCacheProvider如果使用查询缓存,加上hibernate.cache.use_query_cache=true缓存可以简单的看成一个Map,通过key在缓存里面找value。Class的缓存对于一条记录,也就是一个PO来说,是根据ID来找的,缓存的key就是ID,value是POJO。无论list,load还是iterate,只要读出一个对象,都会填充缓存。但是list不会使用缓存,而iterate会先取数据库selectid出来,然后一个id一个id的load,如果在缓存里面有,就从缓存取,没有的话就去数据库load。假设是读写缓存,需要设置:《cacheusage=“read-write“/》如果你使用的二级缓存实现是ehcache的话,需要配置ehcache.xml《cachename=“.xxx.pojo.Foo“maxElementsInMemory=““eternal=“false“timeToLiveSeconds=““timeToIdleSeconds=““overflowToDisk=“true“/》其中eternal表示缓存是不是永远不超时,timeToLiveSeconds是缓存中每个元素(这里也就是一个POJO的超时时间,如果eternal=“false“,超过指定的时间,这个元素就被移走了。timeToIdleSeconds是发呆时间,是可选的。当往缓存里面put的元素超过个时,如果overflowToDisk=“true“,就会把缓存中的部分数据保存在硬盘上的临时文件里面。每个需要缓存的class都要这样配置。如果你没有配置,hibernate会在启动的时候警告你,然后使用defaultCache的配置,这样多个class会共享一个配置。当某个ID通过hibernate修改时,hibernate会知道,于是移除缓存。这样大家可能会想,同样的查询条件,第一次先list,第二次再iterate,就可以使用到缓存了。实际上这是很难的,因为你无法判断什么时候是第一次,而且每次查询的条件通常是不一样的,假如数据库里面有条记录,id从到,第一次list的时候出了前个id,第二次iterate的时候却查询到至号id,那么-是从缓存里面取的,到是从数据库取的,共发送+条sql。所以我一直认为iterate没有什么用,总是会有+N的问题。(题外话:有说法说大型查询用list会把整个结果集装入内存,很慢,而iterate只selectid比较好,但是大型查询总是要分页查的,谁也不会真的把整个结果集装进来,假如一页条的话,iterate共需要执行条语句,list虽然选择若干字段,比iterate第一条selectid语句慢一些,但只有一条语句,不装入整个结果集hibernate还会根据数据库方言做优化,比如使用mysql的limit,整体看来应该还是list快。如果想要对list或者iterate查询的结果缓存,就要用到查询缓存了查询缓存首先需要配置hibernate.cache.use_query_cache=true如果用ehcache,配置ehcache.xml,注意hibernate.以后不是.sf的包名了《cachename=“.sf.hibernate.cache.StandardQueryCache“maxElementsInMemory=““eternal=“false“timeToIdleSeconds=““timeToLiveSeconds=““overflowToDisk=“true“/》《cachename=“.sf.hibernate.cache.UpdateTimestampsCache“maxElementsInMemory=““eternal=“true“overflowToDisk=“true“/》然后query.setCacheable(true);//激活查询缓存query.setCacheRegion(“myCacheRegion“);//指定要使用的cacheRegion,可选第二行指定要使用的cacheRegion是myCacheRegion,即你可以给每个查询缓存做一个单独的配置,使用setCacheRegion来做这个指定,需要在ehcache.xml里面配置它:《cachename=“myCacheRegion“maxElementsInMemory=““eternal=“false“timeToIdleSeconds=““timeToLiveSeconds=““overflowToDisk=“true“/》如果省略第二行,不设置cacheRegion的话,那么会使用上面提到的标准查询缓存的配置,也就是.sf.hibernate.cache.StandardQueryCache对于查询缓存来说,缓存的key是根据hql生成的sql,再加上参数,分页等信息(可以通过日志输出看到,不过它的输出不是很可读,最好改一下它的代码。比如hql:fromCatcwherec.namelike?生成大致如下的sql:select*fromcatcwherec.namelike?参数是“tiger%“,那么查询缓存的key*大约*是这样的字符串(我是凭记忆写的,并不精确,不过看了也该明白了:select*fromcatcwherec.namelike?,parameter:tiger%这样,保证了同样的查询、同样的参数等条件下具有一样的key。现在说说缓存的value,如果是list方式的话,value在这里并不是整个结果集,而是查询出来的这一串ID。也就是说,不管是list方法还是iterate方法,第一次查询的时候,它们的查询方式很它们平时的方式是一样的,list执行一条sql,iterate执行+N条,多出来的行为是它们填充了缓存。但是到同样条件第二次查询的时候,就都和iterate的行为一样了,根据缓存的key去缓存里面查到了value,value是一串id,然后在到class的缓存里面去一个一个的load出来。这样做是为了节约内存。可以看出来,查询缓存需要打开相关类的class缓存。list和iterate方法第一次执行的时候,都是既填充查询缓存又填充class缓存的。这里还有一个很容易被忽视的重要问题,即打开查询缓存以后,即使是list方法也可能遇到+N的问题!相同条件第一次list的时候,因为查询缓存中找不到,不管class缓存是否存在数据,总是发送一条sql语句到数据库获取全部数据,然后填充查询缓存和class缓存。但是第二次执行的时候,问题就来了,如果你的class缓存的超时时间比较短,现在class缓存都超时了,但是查询缓存还在,那么list方法在获取id串以后,将会一个一个去数据库load!因此,class缓存的超时时间一定不能短于查询缓存设置的超时时间!如果还设置了发呆时间的话,保证class缓存的发呆时间也大于查询的缓存的生存时间。这里还有其他情况,比如class缓存被程序强制evict了,这种情况就请自己注意了。另外,如果hql查询包含select字句,那么查询缓存里面的value就是整个结果集了。当hibernate更新数据库的时候,它怎么知道更新哪些查询缓存呢?hibernate在一个地方维护每个表的最后更新时间,其实也就是放在上面.sf.hibernate.cache.UpdateTimestampsCache所指定的缓存配置里面。当通过hibernate更新的时候,hibernate会知道这次更新影响了哪些表。然后它更新这些表的最后更新时间。每个缓存都有一个生成时间和这个缓存所查询的表,当hibernate查询一个缓存是否存在的时候,如果缓存存在,它还要取出缓存的生成时间和这个缓存所查询的表,然后去查找这些表的最后更新时间,如果有一个表在生成时间后更新过了,那么这个缓存是无效的。可以看出,只要更新过一个表,那么凡是涉及到这个表的查询缓存就失效了,因此查询缓存的命中率可能会比较低。Collection缓存需要在hbm的collection里面设置《cacheusage=“read-write“/》假如class是Cat,collection叫children,那么ehcache里面配置《cachename=“.xxx.pojo.Cat.children“maxElementsInMemory=““eternal=“false“timeToIdleSeconds=““timeToLiveSeconds=““overflowToDisk=“true“/》Collection的缓存和前面查询缓存的list一样,也是只保持一串id,但它不会因为这个表更新过就失效,一个collection缓存仅在这个collection里面的元素有增删时才失效。这样有一个问题,如果你的collection是根据某个字段排序的,当其中一个元素更新了该字段时,导致顺序改变时,collection缓存里面的顺序没有做更新。缓存策略只读缓存(read-only:没有什么好说的读/写缓存(read-write:程序可能要的更新数据不严格的读/写缓存(nonstrict-read-write:需要更新数据,但是两个事务更新同一条记录的可能性很小,性能比读写缓存好事务缓存(transactional:缓存支持事务,发生异常的时候,缓存也能够回滚,只支持jta环境,这个我没有怎么研究过读写缓存和不严格读写缓存在实现上的区别在于,读写缓存更新缓存的时候会把缓存里面的数据换成一个锁,其他事务如果去取相应的缓存数据,发现被锁住了,然后就直接取数据库查询。在hibernate.的ehcache实现中,如果锁住部分缓存的事务发生了异常,那么缓存会一直被锁住,直到秒后超时。不严格读写缓存不锁定缓存中的数据。使用二级缓存的前置条件你的hibernate程序对数据库有独占的写访问权,其他的进程更新了数据库,hibernate是不可能知道的。你操作数据库必需直接通过hibernate,如果你调用存储过程,或者自己使用jdbc更新数据库,hibernate也是不知道的。hibernate.的大批量更新和删除是不更新二级缓存的,但是据说.已经解决了这个问题。这个限制相当的棘手,有时候hibernate做批量更新、删除很慢,但是你却不能自己写jdbc来优化,很郁闷吧。SessionFactory也提供了移除缓存的方法,你一定要自己写一些JDBC的话,可以调用这些方法移除缓存,这些方法是:voidevict(ClasspersistentClass)Evictallentriesfromthesecond-levelcache.voidevict(ClasspersistentClass,Serializableid)Evictanentryfromthesecond-levelcache.voidevictCollection(StringroleName)Evictallentriesfromthesecond-levelcache.voidevictCollection(StringroleName,Serializableid)Evictanentryfromthesecond-levelcache.voidevictQueries()Evictanyqueryresultsetscachedinthedefaultquerycacheregion.voidevictQueries(StringcacheRegion)Evictanyqueryresultsetscachedinthenamedquerycacheregion.不过我不建议这样做,因为这样很难维护。比如你现在用JDBC批量更新了某个表,有个查询缓存会用到这个表,用evictQueries(StringcacheRegion)移除了个查询缓存,然后用evict(ClasspersistentClass)移除了class缓存,看上去好像完整了。不过哪天你添加了一个相关查询缓存,可能会忘记更新这里的移除代码。如果你的jdbc代码到处都是,在你添加一个查询缓存的时候,还知道其他什么地方也要做相应的改动吗?----------------------------------------------------总结:不要想当然的以为缓存一定能提高性能,仅仅在你能够驾驭它并且条件合适的情况下才是这样的。hibernate的二级缓存限制还是比较多的,不方便用jdbc可能会大大的降低更新性能。在不了解原理的情况下乱用,可能会有+N的问题。不当的使用还可能导致读出脏数据。如果受不了hibernate的诸多限制,那么还是自己在应用程序的层面上做缓存吧。在越高的层面上做缓存,效果就会越好。就好像尽管磁盘有缓存,数据库还是要实现自己的缓存,尽管数据库有缓存,咱们的应用程序还是要做缓存。因为底层的缓存它并不知道高层要用这些数据干什么,只能做的比较通用,而高层可以有针对性的实现缓存,所以在更高的级别上做缓存,效果也要好些吧。

  ⒅请简述Hibernate工作原理

  ⒆Hibernate工作原理是Configuration读取Hibernate的配置文件和映射文件中的信息,即加载配置文件和映射文件,并通过Hibernate配置文件生成一个多线程的SessionFactory对象。

  ⒇然后,多线程SessionFactory对象生成一个线程Session对象;Session对象生成Query对象或者Transaction对象;可通过Session对象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法对PO进行加载、保存、更新、删除等操作。

  ⒈在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象执行查询操作;如果没有异常,Transaction对象将提交这些操作结果到数据库中。

  ⒉Hibernate它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。

  ⒊Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的JaveEE架构中取代CMP,完成数据持久化的重任。

  ⒋hibernate开发都不用缓存吧

  ⒌hibernate开发都用缓存的。hibernate的缓存有一级缓存、二级缓存和查询缓存。其中一级缓存是必需的,它缓存在会话期间的entity。二级缓存和查询缓存是可选的。

您可能感兴趣的文章:

相关文章