hibernate知识整理
什么是延迟加载?
Hibernate的查询方式有哪些?
如何优化Hibernate?
Hibernate中GET和LOAD的区别?
SQL和HQL有什么区别?
hql 面向对象查询
作用的范围不同:
Inverse是设置在集合元素中的。
Cascade对于所有涉及到关联的元素都有效。
<many-to-one/><ont-to-many/>没有inverse属性,但有cascade属性
执行的策略不同
Inverse 会首先判断集合的变化情况,然后针对变化执行相应的处理。
Cascade 是直接对集合中每个元素执行相应的处理
执行的时机不同
Inverse是在执行SQL语句之前判断是否要执行该SQL语句
Cascade则在主控方发生操作时用来判断是否要进行级联操作
执行的目标不同
Inverse对于<ont-to-many>和<many-to-many>处理方式不相同。
对于<ont-to-many>,inverse所处理的是对被关联表进行修改操作。
对于<many-to-many>,inverse所处理的则是中间关联表
Cascade不会区分这两种关系的差别,所做的操作都是针对被关联的对象。
总结:
<one-to-many>
<one-to-many>中,建议inverse=”true”,由“many”方来进行关联关系的维护
<many-to-many>中,只设置其中一方inverse=”false”,或双方都不设置
Cascade,通常情况下都不会使用。特别是删除,一定要慎重。
操作建议:
many-to-many关联关系中,一端设置inverse=”false”,另一端设置为inverse=”true”。在one-to-many关联关系中,设置inverse=”true”,由多端来维护关系表
Hibernate一级缓存相关问题
*private transient ActionQueue actionQueue; ----行动队列(标记数据活动)
*private transient StatefulPersistenceContext persistenceContext;----持久化上下文
Book book =(Book) session.get(Book.class,1);// 第一次查询,缓存中没有
System.out.println(book);
Book book2 =(Book) session.get(Book.class,1);// 因为第一次查询,对象已经被放入1级缓存,不会查询数据
System.out.println(book2);
*生成一条SQL语句,返回同一个对象,第一次查询生成SQL,查询对象,将对象放入一级缓存,第二次查询,直接从一级缓存获得
* 测试快照区的使用
*/
@Test
publicvoid demo3(){
// 获得Session
Session session =HibernateUtils.openSession();
// 开启事务
Transaction transaction = session.beginTransaction();
// 查询id 为1 的图书对象
Book book =(Book) session.get(Book.class,1);// 第一次查询,将对象加入一级缓存
System.out.println(book);
book.setName("深入浅出Hibernate技术");// 修改书名(一级缓存被修改,自动update)
// 没有手动执行update,因为快照区原因,自动更新
// 提交事务,关闭Session
transaction.commit();
session.close();
@Test
// Session 对于 一级缓存操作
publicvoid demo4(){
// 获得Session
Session session =HibernateUtils.openSession();
// 开启事务
Transaction transaction = session.beginTransaction();
// 查询id 为1 的图书对象
Book book =(Book) session.get(Book.class,1);// 第一次查询,将对象加入一级缓存
System.out.println(book);
// book.setPrice(80d); // 修改一级缓存数据
// 将缓存内容同步到数据库
// session.flush();
// 清除一级缓存所有数据
// session.clear();
// 清除一级缓存中 指定对象
// session.evict(book);
book.setPrice(30d);// 一级缓存改变
session.refresh(book);// 用数据库内容 覆盖快照区和一级缓存
// 提交事务,关闭Session
transaction.commit();
session.close();
}
@Test
// 理解 FlushMode作用
publicvoid demo5(){
// 获得Session
Session session =HibernateUtils.openSession();
// 设置 flushMode
session.setFlushMode(FlushMode.MANUAL);
// 开启事务
Transaction transaction = session.beginTransaction();
// 查询id 为1 的图书对象
Book book =(Book) session.get(Book.class,1);// 第一次查询,将对象加入一级缓存
System.out.println(book);
book.setPrice(1000d);// 修改价格
session.createQuery("from Book").list();// 查询所有图书 (AUTO 级别 flush)
// 提交事务,关闭Session
transaction.commit();// (COMMIT 级别 flush)
// session.flush(); // MANUAL 级别 flush
session.close();
}
@Test
// 脱管对象更新
publicvoid demo6(){
// 获得Session
Session session =HibernateUtils.openSession();
// 开启事务
Transaction transaction = session.beginTransaction();
Book book =newBook();// 瞬时
book.setId(1);// 脱管
book.setName("java入门");
book.setPrice(40d);
session.update(book);// 持久
session.flush();
// book.setPrice(50d);
// 提交事务,关闭Session
transaction.commit();
session.close();
}
<classname="cn.itcast.domain.firstcache.Book"table="book"catalog="hibernate3day2"select-before-update="true">
@Test
// 一级缓存 存在两个相同OID 持久态对象 报错
publicvoid demo7(){
// 获得Session
Session session =HibernateUtils.openSession();
// 开启事务
Transaction transaction = session.beginTransaction();
// 查询
// Book b = (Book) session.get(Book.class, 1); // 持久
Book book =newBook();// 瞬时
book.setId(1);// 脱管
book.setName("java入门");
book.setPrice(50d);
session.update(book);// 持久
// 提交事务,关闭Session
transaction.commit();
session.close();
}
@Test
// PO对象,OID为 hbm文件 配置 unsaved-value 也是瞬时对象, saveOrUpdate 执行 save操作
publicvoid demo8(){
// 获得Session
Session session =HibernateUtils.openSession();
// 开启事务
Transaction transaction = session.beginTransaction();
Book book =newBook();// 瞬时
book.setId(-1);// 存在OID , -1是unsaved-value 也是瞬时
book.setName("xxx");
book.setPrice(100d);
session.saveOrUpdate(book);
// 提交事务,关闭Session
transaction.commit();
session.close();
}
Hibernate二级缓存相关问题
缓存好处: 将数据库或者硬盘数据,保存在内存中,减少数据库查询次数,减少硬盘交互,提高检索效率
hibernate 共有两个级别的缓存
* 一级缓存,保存Session中, 事务范围的缓存
* 二级缓存,保存SessionFactory ,进程范围的缓存
SessionFacoty 两部分缓存
内置 :Hibernate 自带的, 不可卸载. 通常在 Hibernate 的初始化阶段, Hibernate 会把映射元数据和预定义的 SQL 语句放到SessionFactory 的缓存中, 映射元数据是映射文件中数据的复制, 而预定义 SQL 语句时 Hibernate 根据映射元数据推到出来的. 该内置缓存是只读的.
外置 :一个可配置的缓存插件. 在默认情况下, SessionFactory 不会启用这个缓存插件. 外置缓存中的数据是数据库数据的复制, 外置缓存的物理介质可以是内存或硬盘,必须引入第三方缓存插件才能使用。
* 更新时间戳区域
* 查询缓存区域
** 一级缓存的操作会同步到二级缓存
更新时间戳区域
作用:记录数据最后更新时间,确保缓存数据是有效的
Hibernate 提供了和查询相关的缓存区域:
时间戳缓存区域存放了对于查询结果相关的表进行插入, 更新或删除操作的时间戳. Hibernate 通过时间戳缓存区域来判断被缓存的查询结果是否过期, 其运行过程如下:
T1 时刻执行查询操作, 把查询结果存放在 QueryCache 区域, 记录该区域的时间戳为 T1
T2 时刻对查询结果相关的表进行更新操作, Hibernate 把 T2 时刻存放在 UpdateTimestampCache 区域.
T3 时刻执行查询结果前, 先比较 QueryCache 区域的时间戳和 UpdateTimestampCache 区域的时间戳, 若 T2 >T1, 那么就丢弃原先存放在 QueryCache 区域的查询结果, 重新到数据库中查询数据, 再把结果存放到 QueryCache 区域; 若 T2 < T1, 直接从 QueryCache 中获得查询结果。
* 二级缓存缓存数据都是类对象数据,数据都是缓存在 "类缓存区域" ,二级缓存缓存PO类对象,条件(key)是id
查询缓存适用场合:
**应用程序运行时经常使用查询语句
**很少对与查询语句检索到的数据进行插入, 删除和更新操作
如果查询条件不是id查询, 缓存数据不是PO类完整对象 =====> 不适合使用二级缓存
查询缓存: 缓存的是查询数据结果, key是查询生成SQL语句 , 查询缓存比二级缓存功能更加强大
2)启用查询缓存 hibernate.cfg.xml
<property name="hibernate.cache.use_query_cache">true</property>
query.setCacheable(true);
transactional : 提供Repeatable Read事务隔离级别,缓存支持事务,发生异常的时候,缓存也能够回滚
read-write : 提供Read Committed事务隔离级别,更新缓存的时候会锁定缓存中的数据
nonstrict-read-write :导致脏读, 很少使用
read-only : 数据不允许修改,只能查询
* 很少被修改,不是很重要,允许偶尔的并发问题, 适合放入二级缓存。考虑因素(二级缓存的监控【后面学习】,它是是否采用二级缓存主要参考指标)
* OSCache
可作为进程范围内的缓存, 存放数据的物理介质可以是内存或硬盘, 提供了丰富的缓存数据过期策略, 对 Hibernate 的查询缓存提供了支持
* SwarmCache
可作为集群范围内的缓存, 但不支持 Hibernate 的查询缓存
* JBossCache
可作为集群范围内的缓存, 支持 Hibernate 的查询缓存