Hibernate:
一、什么是Hibernate
DAO层很有规律,插入数据的时候,无非就是把pojo拆分成各种属性,然后拼装为SQL语句,保存进数据库;读取数据时,无非就是用SQL把POJO的各种属性从数据库读出来,然后拼装为POJO对象返回。当然POJO与数据表,POJO属性与数据表的列,存在某种固定的映射关系。如果能用程序自动生成SQL语句就好了。ORM框架就是做这种工作的框架(通过配置文件或者注解把JAVA对象映射到数据库上,自动生成SQL
语句并执行
)。而Hibernate 是ORM框架的一种。
Hiberate 充当了DAO层,自动生成SQL语句并执行。
二、宏观理解Hibernate
-
可以做到数据库无关性,只要配置SQL方言(Dialect)。
-
可持久化对象(Persistent Object)的状态
临时状态:数据库中没有该对象,id也为空。如果没有持久化,退出程序,数据丢失
持久化状态:对象保存数据库后或者从数据库加载后,且没有脱离session,可以执行任务数据库操作
分离状态:不可做任何数据库操作,但有id,且数据库有对应记录。三种状态之间的转换:
new 出来的对象是瞬时状态 -> 保存到数据库中,并受 session管理,就是持久化状态 ->将session 关闭就是游离状态。 -
一个SessionFactory 维护一个数据库。有多个数据库,可以创建多个SeeionFactory。
使用Hibernate时需要先创建一个Session 对话,然后开启事务,读写操作,提交事务,关闭会话。
三、Hibernate 工作原理:
- 读取并解析配置文件
- 读取并解析映射信息,创建SessionFactory(单例的,是线程安全的)
- 打开Session(即openSession(),需要手动开启关闭事务。如果改成getCurrentSession,会自动绑定当先前线程,这个线程是有事务的由Spring管理,不需要我们手动管理)
- 创建事务Transaction
- 持久化操作
- 提交事务
- 关闭session
- 关闭SessionFactory
Hibernate的openSession和getCurrentSession的区别:
- getCurrentSession 会绑定当前线程,openSession不会,因为把Hibernate交给Spring管理之后,是有事务配置的,这个有事务配置的线程会绑定当前工厂里的每一个session,而openSession是创建一个新的session。
- getCurrentSession事务是由Spring 控制的,openSession需要程序员手动开启和提交以及关闭事务
- getCurrentSession需要手动设置绑定事务的机制,有三种方式,即:jdbc本地的Thread、JTA、sping提供的事务管理机制sessionContext
四、Hibernate的三种检索策略:
-
立即检索
- 优点:对应用程序完全透明不管对象处于持久化状态还是游离状态,应用程序都可以很方便的从一个对象导航到与它关联的对象
- 缺点:select 语句太多;浪费内存空间,加载了应用程序不需要访问的对象
- 实现方式:lazy=false;
-
延迟检索
- 优点:由应用程序决定需要加载哪些对象,可以避免执行多余的select和节省内存空间,能提高检索效率
- 缺点:应用程序想访问游离状态代理类实例,就必须保证在持久化状态时已经被初始化
- 实现方式:lazy=true;
-
迫切左外连接检索
- 优点:对应用程序完全透明,同立即检索的优点;使用外连接,减少了select语句
- 缺点:a. 可能会加载应用程序不需要访问的对象,浪费内存空间;b.复杂的数据库表连接会影响检索性能
- 实现方式:预先抓取:fetch = “join”;
五、Hibernate 缓存
缓存内的数据是对物理数据源数据中数据的复制。
作用:hibernate是一个持久层框架,经常访问物理数据库,为了提高应用程序运行的性能,就需要减少应用程序访问物理数据库的次数。
-
一级缓存(也叫session缓存):
作用:可以减少对数据库的访问次数,从而提高性能。但是是在session 范围内才有效,一旦session关闭,缓存就失效了。
如何判断是否是session缓存?
只要是持久化对象状态的,都在Session缓存中
维护:Session 缓存由Hibernate 维护,程序员不能操作缓存内容,非要操作,就需要通过Hibernate提供的evit(清除指定对象缓存)/clear(清空all)方法了 -
二级缓存(又叫SessionFactory的缓存):基于应用程序的缓存,所有的Session都可以使用。
Hibernate二级缓存是一种可插配的缓存框架,需要用的时候,可以在Hibernate.cfg.xml文件中配置。
什么样的数据适合存放到二级缓存中?
- 很少被修改的数据
- 不是很重要的数据,允许出现偶尔并发的数据
- 不会被并发访问的数据
- 常量数据
总结:存储的都是常用的类
不适合存放到第二级缓存的数据?
- 经常被修改的数据
- 绝对不允许出现并发访问的数据,如财务数据,绝对不允许出现并发
- 与其他应用共享的数据。
-
Hibernate查找对象如何应用缓存?
当Hibernate根据ID访问
数据对象时,首先查找一级缓存,找不到就查二级缓存(二级缓存配置了的话),还查不到,就会去查数据库,然后把结果按照ID放入到缓存
,增删改数据的时候同时更新缓存。 -
Hibernate管理缓存实例
在管理缓存时,当给save(),update(),saveOrUpdate(),传递一个对象
时,或者使用load(),list(),Iterate(),scroll()获得一个对象
时,该对象都会被加入到session缓存中。调用flush()方法,会刷新缓存,缓存数据和物理数据库保持一致。调用evict()或者clear()方法会清除缓存
六、Hibernate 的版本属性:
- 版本(Version)属性是Hibernate中一种特殊属性。该属性不参与业务逻辑,只用来保证不会有两个线程同时对数据进行写操作。是乐观锁的一种实现方式。
悲观锁和乐观锁都是摆正数据正确性的机制。 乐观锁
:通过Version列保存当前数据的版本,如果程序修改了数据,就将版本加1。程序保存数据时会检查数据的Version列,如果该列发生了变化,程序会重新读取,修改并保存该数据。该机制不需要锁住行,允许多条线程同时访问同一条数据,故称为乐观锁。悲观锁
:程序修改数据时先锁住该数据行,是其他程序无法修改改行数据,修改完释放数据锁,以保证数据的准确性。因为该机制需要锁定数据行,同一时间只能有一个线程访问,故被称为悲观锁。
七、如何优化Hibernate?
- 数据库设计调整
- HQL 优化
- API的正确使用(如根据不同的业务类型选用不同的集合及查询API)
比如即时加载策略时,如果是统计个数,可以不使用.size(),可以使用count(*) - 主配置参数(日志,查询缓存,fetch_size, batch_size等)
- 映射文件优化(ID生成策略,二级缓存,延迟加载,关联优化)
- 一级缓存的管理
八、Hibernate 的查询方式
- 对象导航查询
- HQL查询
- 1.属性查询
- 2.参数查询、命名参数查询
- 3.关联查询
- 4.分页查询
- 5.统计函数
- Criteria 查询
- 原生SQL查询
九、主键生成策略
identify
:主键自增,由数据库维护主键值,录入时不需要手动指定主键值increment
:主键自增,由hibernate维护,每次插入前会查表中id最大值+1作为主键(存在线程安全问题)1sequence
:Oracle中的主键生成策略native
: 自增长【会根据底层数据库自增长的方式选择identity或sequence】mysql数据库采用identify,Oracle采用sequencehilo
:高地位算法,主键自增,hibernate维护,开发不使用assigned
:自然主键生成策略,Hibernate不会管理,有程序员自己录入,如果不设id,就会报错uuid
:产生随机字符串,主键类型必须是String类型