l缓存是存储数据的临时空间,减少从数据库中查询数据的次数
lHibernate中提供有两种缓存机制
•一级缓存(Hibernate自身携带)
•二级缓存(使用外部技术)
lHibernate的一级缓存即Hibernate操作数据时所对应的临时数据存储区域,这个区域是绑定Session对象的,也就是说每开启一个Session对象,就会产生对应的一级缓存空间,当Session对象关闭时,该空间内的数据,也就是其中保存的PO对象,会转化为DO对象。
lHibernate的一级缓存是Session级别的缓存,与Session对象一一对应,不同的Session间无法共享缓存数据。
l验证Hibernate一级缓存的存在性
lget与load方法的区别
•相同:load与get方法查询数据,首先查找一级缓存中是否存在待查找数据,如果存在,直接获取;如果不存在,从数据库中通过SQL语句获取数据库端对应的数据
•不同:load方法查询到的对象,如果只获取数据的OID则不进行任何查询,直接返回OID;如果需要使用OID之外的数据,则按照上述规则查找对应的数据
l通过配置可以关闭延迟加载——lazy属性
Hibernate延迟加载开启与关闭
l在映射文件.hbm.xml文件中,可以配置是否使用延迟加载特性,可以将该属性配置在三个位置
Hibernate使用一级缓存
lHibernate的一级缓存可以理解为数据的中转站
lHibernate进行数据R操作
•如果一级缓存中存在该数据,直接取出使用
•如果一级缓存中不存在,执行SQL语句从数据库中获取
lHibernate进行数据CUD操作
•将待操作的数据及操作模式放入一级缓存
•刷新一级缓存,检测是否需要进行持久化
Hibernate一级缓存刷新方式
lHibernate的一级缓存中保存有本次Session操作过程中的所有数据,这些数据在如下情况提交到数据库进行同步更新,对需要进行更新的数据执行对应的SQL语句
•执行事务提交
•t.commit();
•刷新Session范围的缓存数据
•s.flush();
•关闭Session
•s.close();
Hibernate刷新一级缓存——快照
l当任意数据进入Hibernate一级缓存中时,马上保存该数据的一份克隆(快照),当一级缓存刷新时,对每一个缓存中的对象进行比对,如果快照数据与当前数据相同,无任何操作;如果快照数据与当前数据不同,则将修改后的数据更新到数据库中,执行对应的SQL语句,并更新快照数据
l一级缓冲中保存的对象全是PO,因此PO可以更新数据库对应信息,而TO与DO则不具备这样的能力
l刷新一级缓存
•s.flush();
l清除一级缓存
•s.clear();
l清除一级缓存中指定对象
•s.evict(obj);
l更新一级缓存中指定对象(使用数据库中数据覆盖一级缓存数据及快照数据)
•s.refresh(obj);
Hibernate一级缓存刷新时机
l所谓Hibernate一级缓存刷新时机指一级缓存中存在的修改数据何时会被同步到数据库表中
l常用的刷新时机有四种(FlushModel常量)
•ALWAYS:任意操作导致刷新(效率过低)
•AUTO:根据操作功能区别是否刷新(默认)
•COMMIT:提交事务时刷新
•MANUAL:手动执行刷新时进行刷新(关闭session不会触发)
l设置方式:
•s.setFlushMode(FlushMode.COMMIT);
•设置在Session对象获得后
Hibernate一级缓存常用操作注意事项
lsave()
lupdate()
lmerge()
lsaveOrUpdate()
lget()/load()
ldelete()
lsave操作可以将一个TO转换为PO
l操作步骤:
•将TO装入Session,TO→PO
•使用ID生成器,为PO分配唯一标识OID
•如果手工给出了OID,生成器会根据配置将此OID进行替换
•在执行计划中添加INSERT语句,通过映射文件中的配置,将对象中的属性值添加到INSERT语句中
l注意:
•TO执行了save操作后,TO转换为PO,此时如果修改PO的OID,那么会产生错误,通知用户一个PO的OID发生了变化,这是不被允许的
lupdate操作可以将一个DO转换为PO
l操作步骤:
•为一个TO指定OID,TO→DO
•使用update更新DO,DO→PO
•在执行计划中添加UPDATE语句,通过映射文件中的配置,将对象中的属性值添加到UPDATE语句中
l注意:
•DO转化PO使用update语句完成,如果在转化完成后对PO进行属性更新,只会产生一条update语句,此时PO状态的改变会在缓存进行刷新时才完成最终操作,除非提前刷新缓存
•PO的更新不使用update语句,缓存刷新时自动完成
lUpdate将DO→PO操作会强制完成一次更新操作,无论数据是否发生变化,此时可根据业务需要选择
•如果用户数据没有发生变化,则不执行update语句
•如果用户数据发生了变化,则执行update语句
l完成上述操作的前提是将update操作对应的数据先与数据库中的数据进行比对,也就是update操作前执行查询语句select,可以通过配置完成上述操作
•在class元素中配置select-before-update,该配置值默认false
l注意:此设定开启后,整体效率会下降,慎重选择.
lupdate操作将DO转换为PO后,最终将执行对应的UPDATE语句将数据持久化到数据库中,此时如果数据库表中不存在对应OID的数据,程序也将出错
•该错误隶属于基本的SQL操作,SQL语句更新一个不存在的东西将产生0行数据影响的一个操作,而对于Hibernate将此现象归属于执行了一个不可能完成的任务,最终以异常的形式展示给开发者
•例如:A用户读取了一条数据,准备修改该数据,此时B用户将这条数据删除了,A用户在修改该数据时,该数据已经消失,造成上述问题的出现,后期可以通过配置的形式避免该现象的发生,但是效率非常低下。实际业务中,只需要给用户一个合理的提示就行了。
lupdate操作可以将DO转换为PO,但是如果此时Session范围内存在有相同OID的PO对象,此时将报错
l总结:任意时间,同一个Session范围内,不管通过何种方式,如果两个PO具有了同样的OID,那么Hibernate无法区分两个对象,此时将报错
lupdate操作将DO转化为PO时,如果Session范围内存在有相同OID的PO,那么程序将报错。如果要将DO继续转化为PO,可以将两个对象合并成一个,使用merge操作可以完成对象的合并。
lmerge操作是将当前操作的DO属性,合并到OID相同的PO上,最终属性以最后一次修改的为准。如果没有与DO的OID相同的PO,那么merge操作将执行update操作,将DO转化为PO
•存在相同OID的PO,DO合并属性到PO
•不存在相同OID的PO,DO转化为PO
s.merge(um);
lsaveOrUpdate操作是根据对象的状态执行对应操作
•TO执行save操作
•PO无任何操作
•DO执行update操作
l注意:TO的判定标准
•对象的OID为null
•在hbm.xml文件中,为id元素指定unsaved-value属性值,且对象的OID的值与其相同
lget与load方法都可以根据传入的OID值从数据库中获取对应的记录信息,并转换为PO
lget与load读取时加载策略不同(前面已讲解)
lget与load获取数据的区别:
•当DB中不存在get操作获取的OID数据时返回null
•当DB中不存在load操作获取的OID数据时,抛异常
•load方法返回的不是模型对象,而是模型对象的代理对象,因此对于模型类不能使用final修饰,否则将无法创建代理对象
ldelete操作可以从数据库表中删除一条对应的记录
ldelete操作运行原理
•delete操作删除某个对象时,只能对PO进行操作
•如果是DO,首先关联到Session,将DO转化为PO
•TO无法删除
•执行delete操作,在Session范围内对待删除的数据进行删除标记的添加,此时,该对象已经被标记为被删除对象,但还未执行删除语句,数据库中还存在该记录
•刷新缓存时,执行真正的DELETE语句