对象操作
实体状态
自由状态……实体对象在内存中自由存在,与数据库中的记录没有任何关联,处理自由状态的实例可以通过Session的save方法转换成持久状态。
持久状态……实体对象处于由Hibernate框架所管理的状态,持久状态的对象其变更将由Hibernate固化到数据库中,持久对象对应数据库中的一条记录。
游离状态……处于持久状态的实例,其关联的会话已经关闭,则此实例处于 游离状态。 游离状态的实例可以通过Session的update方法再次和一个会话关联。
游离状态和自由状态实例的区别是自由状态的实例与数据库缺乏对应关系,而游离状态的实例包含对应数据库记录的主键值。
实体身份识别
从数据库的角度,包括Hibernate本身对于拥有同样主键值的实体对象则认为他们是相同的。在持久层之外,对象是否等价在业务逻辑层可能有另外的含义,往往有一些特定的数据实体判定规则,这可以通过重写equals和hashCode方法实现。
脏数据检查
脏数据检查策略一般有两种方式:
数据对象监控:可以借助动态代理或CGLIB拦截设值方法,一旦设值方法被调用,则将其标记为脏状态。
数据版本比对:持久层框架维持数据对象的最新版本,当数据提交时将提交数据和此版本进行比对,如果发生变化则将其同步到数据库相应的库表。
Hibernate采用数据版本比对方式,Hibernate会话保存所有与当前会话关联实体的当前实例和原始状态信息,可以参见SessionImpl的内部类EntityEntry。
Load/Get
这两个操作的功能都是从数据库中加载一个实例,两者的区别是前者如果没有找到匹配数据将抛出异常,后者将返回null。
List/Iterate
这两个操作的功能都是从数据库中加载多个实例,两者的区别是Iterate方法会先从会话中或者二级缓存中获取,而list方法会直接查询数据库,如果需要的数据在缓存中存在,iterate可以提供更好的性能,相反的情况下iterate方法会更慢,它会首先执行查询仅从数据库中获取标识符,然后再分别查询初始化实例。
Update/Merge
这两个操作都支持分离实例的重新关联。如果会话中已经包含同样标识符的实例,update方法会抛出异常,merge方法会合并更改再重新关联。
Flush
Flush方法的主要功能是同步内存对象和数据库,flush操作缺省发生在一些查询操作之前,事务提交时或者调用flush方法时。
显式调用flush方法并不能保证立即执行数据库同步,Hibernate保证Query.list方法不会返回过时或错误数据。
可以通过Session.setFlushMode改变缺省行为,不至于太频繁。FlushMode定义了三种不同的刷新方式:提交时刷新,自动刷新,不刷新(除非显式调用flush方法)。
提交时刷新可能会导致查询操作获取过时数据。
级联
Hibernate会话的基本操作,包括persist,merge,saveOrUpdate等都有相应的级联样式设置,如果你希望关联集合针对某个操作进行级联设置,可以在映射文件中设置,示例如下:
xml 代码
缺省的级联设置是none,表示任何操作都不支持级联。
级联通常用在在一对一和一对多关系中。
继承映射
单表映射
概述: 使用一张表映射整个继承树,需要一个类别字段区分一个数据行具体对应哪个类。
优点:有很好的查询性能,不需要进行表连接。
缺点:有数据冗余。子类的字段无法建立非空约束。
类表映射
概述:每个类对应一张表。子类表只包含扩展属性,子类表和父类表通过外键关联。
优点:领域模型和数据库之间的关系非常明了。
缺点: 查询时需要多表之间的内连接或左外连接操作。字段在层次中任何上下移动的重构都会导致数据库更改。
具体表映射(UNION)
概述:每个具体类对应一张表,包含所有的字段。使用union-class进行定义。
优点:与具体表映射(隐式多态)相比,支持多态查询。
缺点:具体类不支持标识生成器,标识生成器在所有的具体类中共享。如果某个属性在超类中进行映射,则其列名在所有的子类表中必须相同。
具体表映射(隐式多态)
概述:每个具体类对应一张表,包含所有的字段。
优点:查询子类时不需要关联。
缺点:如果父类字段发生变动,所有的子类表必须同时进行修改。超类上的一次查找需要检查所有表,这会导致多次数据库访问或特殊连接操作。不支持多态外连接抓取数据。不支持多态一对一和一对多关联。
集合映射
Hibernate要求实体的集合字段必须声明为接口类型,当持久化实体时,Hibernate会使用自己的集合实现。因此假定使用HashSet初始化实体的集合字段,经过持久化后得到的集合字段并不是HashSet的实例,如果进行转型将发生错误。
有序/无序
Hibernate支持Set,Bag,Map三种无序集合,List是有序集合,这里所谓的有序无序是指Hibernate持久化过程中,是否保持数据集合中的记录排列顺序。
可配置属性
Lazy……缺省为true,表示不加载关联的集合。
Cascade……缺省为none,表示不级联操作集合。
Fetch……缺省为select,可以设置为join使用连接检索模式。
optimistic-lock……缺省为true,表示集合状态的改变会导致拥有集合的实体的版本增加,如果是一对多关联,通常设置为false。
Inverse
缺省为false,如果为true,表示关联由另一端管理。
Sort/Order-by
Sort/Order-by属性用来设置集合排序,前者表示排序基于内存操作的,后者表示数据库检索时进行排序,通过指定SQL语句的order by部分来实现。
外键信息
使用key元素进行定义。
元素类型
使用element和composite-element定义值类型,使用one-to-many和many-to-many定义实体类型。
索引集合
除SET和BAG外,其他集合都需要指定集合表中的索引列,LIST和ARRAY使用list-index元素定义,MAP集合使用map-key/composite-map-key或map-key-many-to-many定义。
List/Bag
如果希望使用list声明集合字段,而表中又没有索引列,那么可以使用bag元素定义映射,bag元素不具备list的有序特性。
Bag/idBag
Bag 类型是Hibernate自定义集合类型,实现一个允许包含重复元素的Set,因为Bag集合为无序集,且允许出现重复元素,这出现一个问题,当删除某个元素时如何定位待删除记录?目前的实现方式是先将表中原有的集合数据全部删除,再将现有数据逐条插入,显然这种方式的性能是极其低下的。
idBag对此进行了扩展,提供一个collection-id元素用来配置id字段,根据此id,Hibernate可以准确定位库表记录,从而实现高效的数据操作。
事务/并发
Hibernate直接使用JDBC和JTA资源的事务语义,没有添加额外的锁机制。SessionFactory是线程安全的,可以被所有的应用线程共享。Session是线程不安全的,通常用于单个请求,单个会话或单个工作单元。
通常不管读写数据,数据库交互都应该发生在事务语义中。
在多用户的C/S应用程序中,最通用的模式是基于请求的会话,使用单个的数据库事务服务整个客户请求,在WEB企业应用程序中,数据库事务跨越用户交互是无法接受的。
会话会缓存每个处理持久状态的实例,这意味着如果保持会话打开一段比较长的时间,可能导致内存不足,也可能导致过时数据。一个解决方法是调用clear和evict方法管理会话,但是更应该考虑使用存储过程处理大数据量操作。
乐观并发访问
支持高并发性和高扩展性的唯一方式是使用版本的乐观并发控制。版本检查使用版本号或时间戳来检查更新。Hibernate提供三种方式使用乐观并发控制。
手动版本检查:每次数据库操作发生在一个新的会话中,开发者有责任在操作之前加载所有的持久化实例,手动执行版本检查。这种方式是最低效的,类似于实体EJB的方式。
扩展会话方式的自动版本检查:Hibernate基于一次交互创建一个会话,在每次执行刷新时检查实例的版本,如果检测到并发更改将抛出异常,由开发人员负责捕获和处理异常。这种方式是最有效的,应用不必关心版本检查,不必重新关联分离状态的实例,也不必在每次数据库事务前重新加载所有的实例。
分离状态实例的自动版本检查:应用可以操纵一个分离状态的实例的属性,这个实例是在另一个会话加载的,然后再和一个新的会话重新关联(通过调用update或saveOrUpdate方法),当新会话刷新时会自动执行版本检查。
自定义版本检查:也可以通过设置属性或集合的optimistic-lock值为false禁止自动版本检测,也可以设置Class映射的 optimistic-lock属性为all,通过比较实例的所有字段进行版本检查,有时候并发更改只要没有发生叠加也是允许的,这可以通过设置 optimistic-lock属性为dirty实现。
悲观锁
通常情况下用户不需要共太多时间关心锁策略,通过对JDBC连接指定隔离级别可以让数据库负责这些工作,然而高级用户可能需要获取排他锁或启动新事务时重新获取锁。
Hibernate总是使用数据库的锁机制,LockMode类定义了Hibernate可以获得的锁级别,这可以通过Session的lock/load方法和Query的setLockMode方法进行操纵。
性能优化
抓取策略
抓取策略是指Hibernate如何检索关联对象,抓取策略可以通过映射设置,也可以在HQL和规则查询中重写。Hibernate支持以下几种抓取策略:
join……使用外连接抓取。
Select……使用一个单独的查询语句抓取关联数据。
Subselect……
Batch……select抓取的优化,通过指定一个主键或外键列表使用一个单独的查询语句中进行抓取。
同时Hibernate区分如下几种抓取方式:
Immediate……立即加载
Lazy……懒加载,需要时加载整个集合
Extra-lazy……按需加载集合中的单个元素,尽量不同时加载整个集合,适用于集合很大的情况。
Proxy……当激活关联对象的某个方法而不是取值方法时检索单值关联。
No-proxy……实例变量被访问时检索单值关联,相比proxy策略,这种方式少一些懒加载,要求构建二进制字节码,很少使用。
Lazy attribute……当实例变量被访问时检索单值关联或属性,这种方式要求构建二进制字节码,很少使用。
以上分别决定什么时候加载以及怎样加载,缺省情况下Hibernate使用lazy select抓取关联集合,使用lazy proxy抓取单值关联。
如果设置hibernate.default_batch_fetch_size,,Hibernate将使用Batch抓取策略。
使用select策略通常会导致n+1次查询,这可以通过使用join策略解决,可以在hql和criteria中调用setFetchMode设置检索策略。
有时候我们需要在会话关闭时,初始化代理和集合,这可以通过Hibernate的initialize和isInitializied方法实现。
有时候你不想初始化一个大的集合,而只是需要集合的一个子集或者集合的大小 ,这时候可以使用集合过滤器,比如要获取集合的大小:
s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();
缓存
Hibernate数据缓存分为两个层次,Session级别的内部缓存,SessionFactory级别的二级缓存。
内部缓存正常情况下由Hibernate自动维护,如果需要手工干预,可以通过如下方法完成:
evict方法从当前缓存中移除某个实例
contains会话中是否包含某个实例
clear用来清除会话。
引入二级缓存必须考虑一些问题:
数据库是否与其他应用共享,如果需要通常必须放弃二级缓存的使用。
应用是否需要部署在集群环境中,此时必须考虑是否需要引入分布式缓存。
应该对哪些数据进行缓存。
如果满足以下条件,则可以考虑二级缓存:
数据不会被第三方应用修改。
数据大小在可接受范围。
数据更新频率较低。
同一数据可能会被系统频繁调用。
非关键数据。
Hibernate缺省使用EHCache作为其二级缓存,SessionFactory提供几个方法用来有效管理二级缓存。
evict清除某个类
evictCollection清除某个集合。
CacheMode用来控制会话如何和二级缓存进行交互,包括NORMAL,READ,WRITE和REFRESH选项。
可以使用Statistics API查询二级缓存,示例如下:
java 代码
Map cacheEntries = sessionFactory.
.getSecondLevelCacheStatistics(
.getEntries();
可以通过设置 hibernate.cache.use_query_cache属性为true启用查询缓存,查询缓存应该总是和二级缓存一起使用。此设置将创建两个缓存区域,一个缓存查询结果,一个缓存对查询表的最近更新的时间戳。大部分查询不会受益于查询缓存,因此缺省设置为false。可以调用 Query.setSacheable方法手动缓存查询结果。
集合性能
所有的索引集合list,array,map都有一个主键包含key和index列,主键可以很容易的被索引,更新删除时也可以很快定位,因此这种集合通常是最有效的。
Set集合有一个主键包含key列和element列,对某些情况,这种集合是低效的,特别是组合元素或者大文本字段,因为数据库可能不能有效索引比较复杂的主键。
IdBag通常是最有效的。
Bag通常是最坏的选择,因为允许重复值,没有索引列,没有主键可以定义,Hibernate没有办法区别重复行,只有通过完全删除和完全重建来响应任何改变,这是相当低效的。
List/map/Idbag/set针对更新操作是最有效的,包括添加/更新/删除。
Set应该Hibernate应用中最常用的集合,因为关系数据库模型中set集合语义是最自然的,然而在设计良好的应用程序中,我们看到大部分集合是 inverse设置为true的一对多关联,这种情况下,bag通常是最有效的集合,因为添加元素到bag和list不需要执行抓取操作(set则不然),此时执行类似下面的代码将会更快
java 代码
Parent p = (Parent) sess.load(Parent.class, id);
Child c = new Child();
c.setParent(p);
p.getChildren().add(c); //no need to fetch the collection!
sess.flush();
性能监听
Statistics接口提供三种类别的统计信息:
Sesssion使用相关的,比如打开的会话数目,检索的JDBC连接数目。
实体,集合,查询和缓存相关的全局信息。
特定实体,集合,查询和缓存区域的详细信息。
具体细节可以参考Statistics, EntityStatistics, CollectionStatistics,
SecondLevelCacheStatistics和QueryStatistics的API文档,示例如下:
java 代码
Statistics stats = HibernateUtil.sessionFactory.getStatistics();
double queryCacheHitCount = stats.getQueryCacheHitCount();
double queryCacheMissCount = stats.getQueryCacheMissCount();
double queryCacheHitRatio =
queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount);
log.info("Query Hit ratio:" + queryCacheHitRatio);
EntityStatistics entityStats =
stats.getEntityStatistics( Cat.class.getName() );
long changes =
entityStats.getInsertCount()
+ entityStats.getUpdateCount()
+ entityStats.getDeleteCount();
log.info(Cat.class.getName() + " changed " + changes + "times" );
分享到:
相关推荐
重读闭音节是英语发音规则中的一个重要概念,主要涉及元音字母在特定音节中的发音方式。在学习英语发音时,理解并掌握这一规则对于准确读出单词至关重要。 首先,我们回顾一下重读开音节。重读开音节指的是在一个...
英语语音重读是英语口语表达中的一个重要组成部分,它关乎到信息的传递清晰度以及语调的自然流畅。在英语句子中,重读的规律主要遵循以下几个原则: 首先,实词通常需要重读。实词包括名词、动词、形容词、副词、...
* 本手册的版本记录包括初始版本、默认重读延迟为 600ms、第二章添加“照明灯”等 * 每个版本的更新内容和发布日期均有记录 六、设备使用指南 * 本手册包括第一章关于 NLS-FR20-BP 的介绍、第二章关于设备的使用...
英语发音规则(重读音节和非重读音节).pdf
【标题】:深入理解Hibernate的事务管理 【摘要】: Hibernate作为一款强大的对象关系映射框架,提供了完善的事务管理机制,以确保数据的完整性和一致性。事务管理是数据库操作的核心,涉及原子性、一致性、隔离性...
在英语发音中,音节划分和元音字母在重读及非重读音节中的发音是关键要素。音节是英语单词发音的基本单位,它由一个或多个字母组成,其中至少包含一个元音。理解这一概念有助于准确地读出单词,并且在口语中表达清晰...
这篇文档实际上是一篇以“重读冰心,感受母爱”为主题的作文,而非与IT行业相关的知识内容。文章通过描述作者对冰心作品的理解,尤其是冰心对母爱的赞美,来表达作者对母爱的深刻感悟和个人经历。母爱在文中被视为最...
重读南京百科知识竞赛题及答案.doc
英语发音中的音节划分和重读规则是学习者掌握地道口语的关键部分。下面将详细解释这些规则,并通过实例帮助理解。 一、单词重读 1. 双音节词的重读规则: a) 大多数双音节词的第一个音节重读,如 "letter"、...
音节划分元音字母在重读非重读中发音.ppt
本文主要探讨了元音字母在重读和非重读音节中的读音规则,这对于学习英语发音和词汇记忆至关重要。 首先,我们来看元音字母在重读音节中的读音: 1. 开音节:在开音节中,元音字母通常会发其"字母名称"的音。例如...
【音节划分与音节重读】是英语学习中的重要概念,主要涉及到单词发音的准确性。音节划分是将单词分解成若干个发音单位,每个单位由一个或多个字母组成,至少包含一个元音字母。以下是对音节划分规则的详细解释: 1....
在教师资格证初中英语语音试讲中,重点是教授如何理解和使用正确的语音技巧,特别是重读和语调。试讲稿中的内容展示了一个日常生活场景,爷爷找不到他的眼镜,请求孙女李兰帮忙,但因为听力问题,他们之间发生了一些...
在英语学习中,音节划分、重读规则和读音规则是至关重要的基础部分,它们直接影响到单词的发音和语句的理解。以下是对这些规则的详细解释: 首先,我们来看单词的重读规则: 1. 双音节词: a) 通常第一个音节重读...
由于提供的文件内容为乱码,并且文件标题为"消费行业四大行业消费趋势电·重读消费者.pdf",但无法从乱码内容中提取实际信息,我将基于文件的标题和描述来猜测内容,并生成相关知识点。 【标题】"消费行业四大行业...
3. **故障排除**:如果遇到问题,首先重读手册,检查操作步骤和电缆连接,参考手册末尾的“故障排查”部分。如果问题仍未解决,应联系购买投影机的销售商或服务中心寻求帮助。 4. **清洁与维护**:定期清理投影机,...
【开音节与重读音节】 在英语发音中,开音节是一个重要的概念,它涉及到单词中的元音字母如何发音。开音节是指以一个元音字母结尾,且这个元音字母在其后没有受到其他辅音字母的影响,能够自由地发出其基本音,也...
这些书籍的出现,似乎在暗示重读不仅仅是个人习惯,它还是一种文化现象,一种阅读的新趋势。 重读旧书,对于许多人来说,不仅仅是因为怀旧或者时间有限。它是一种深度阅读的方式,让人们有机会更深入地理解文本,...
英语发音规则(重读、轻读、略读、浊音) 英语发音规则是英语学习的重要组成部分,对于英语学习者来说,掌握正确的发音规则是非常必要的。本文将详细讲解英语发音规则,包括重读、轻读、略读和浊音等内容。 一、...
- 当遇到不确定的条码类型或配置需求时,可以参考手册的附录部分,通过条码表和类型表进行查找和设置。 - 在进行串口参数设置时,要注意不要随意更改出厂默认设置,除非有充分理由,并且确信新的参数设置不会导致...