Hibernate 是一个开源框架,它是对象关联关系映射的框架,它对 JDBC 做了轻量级的封装,使 java 程序员可以使用面向对象的思想来操纵数据库。
Hibernate 核心接口
- session:负责被持久化对象 CRUD 操作
- sessionFactory:负责初始化 hibernate,创建 session 对象
- configuration:负责配置并启动 hibernate,创建 SessionFactory
- Transaction:负责事物相关的操作
- Query 和 Criteria 接口:负责执行各种数据库查询
为什么要用 Hibernate
- 对 JDBC 访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码
- Hibernate 是一个基于 JDBC 的主流持久化框架,是一个优秀的 ORM 实现。它很大程度的简化了 DAO 层的编码工作
- Hibernate 使用 Java 反射机制,而不是字节码增强程序来实现透明性
- Hibernate 的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系
什么是 ORMapping ?
对象关系映射(Object Relational Mapping,简称ORM)是一种为了解决面向对象与关系数据库存在的互不匹配现象的技术。简单的说,ORM 是通过使用描述对象和数据库之间映射的元数据,将 java 程序中的对象自动持久化到关系数据库中。本质上就是将数据从一种形式转换到另外一种形式。 这也同时暗示者额外的执行开销;然而,如果 ORM 作为一种中间件实现,则会有很多机会做优化,而这些在手写的持久层并不存在。
Hibernate 的缓存机制
Hibernate 缓存的作用(即为什么要用缓存机制),然后再具体说说 Hibernate 中缓存的分类情况,最后可以举个具体的例子。
Hibernate 缓存的作用:Hibernate 是一个持久层框架,经常访问物理数据库,为了降低应用程序对物理数据源访问的频次,从而提高应用程序的运行性能。缓存内的数据是对物理数据源中数据的复制,应用程序在运行时从缓存读写数据,在特定的时刻或事件会同步缓存和物理数据源的数据。
Hibernate 缓存分类:Hibernate 缓存包括两大类:Hibernate 一级缓存和 Hibernate 二级缓存。
Hibernate 一级缓存又称为“Session的缓存”,它是内置的,不能被卸载。由于 Session 对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。一级缓存是必需的,不允许而且事实上也无法卸除。在第一级缓存中,持久化类的每个实例都具有唯一的 OID。
Hibernate 二级缓存又称为“SessionFactory的缓存”,由于 SessionFactory 对象的生命周期和应用程序的整个过程对应,因此 Hibernate 二级缓存是进程范围或者集群范围的缓存,有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。第二级缓存是可选的,是一个可配置的插件,在默认情况下,SessionFactory 不会启用这个插件。
什么样的数据适合存放到第二级缓存中 ?
很少被修改的数据;不是很重要的数据,允许偶尔出现并发;不会被并发访问的数据;常量数据
不适合存放到第二级缓存的数据 ?
经常被修改的数据;绝对不允许出现并发访问的数据,如财务数据;与其他应用共享的数据
Hibernate 查找对象如何应用缓存?
当 Hibernate 根据 ID 访问数据对象的时候,首先从 Session 一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;如果都查不到,再查询数据库,把结果按照 ID 放入到缓存,删除、更新、增加数据的时候,同时更新缓存。
Hibernate 的懒加载机制
懒加载(lazy)就是延迟加载。至于为什么要用懒加载呢,就是当我们要访问的数据量过大时,明显用缓存不太合适,因为内存容量有限,为了减少并发量,减少系统资源的消耗,我们让数据在需要的时候才进行加载,这时 Hibernate 用懒加载机制来弥补这种缺陷,但是这只是弥补而不是用了懒加载总体性能就提高了。
-
对于 Hibernate get 方法,Hibernate 会确认一下该 id 对应的数据是否存在,首先在 session 缓存中查找,然后在二级缓存中查找,还没有就查询数据库,数据库中没有就返回 null。
-
Hibernate load 方法加载实体对象的时候,根据映射文件上类级别的 lazy 属性的配置(默认为true),分情况讨论:
-
若为 true,则首先在 Session 缓存中查找,看看该 id 对应的对象是否存在,不存在则使用延迟加载,返回实体的代理类对象(该代理类为实体类的子类,由CGLIB动态生成)。等到具体使用该对象(除获取OID以外)的时候,再查询二级缓存和数据库,若仍没发现符合条件的记录,则会抛出一个 ObjectNotFoundException。
-
若为false,就跟 Hibernateget 方法查找顺序一样,只是最终若没发现符合条件的记录,则会抛出一个 ObjectNotFoundException。
-
这里 get 和 load 有两个重要区别:
-
如果未能发现符合条件的记录, Hibernate get 方法返回 null,而 load 方法会抛出一个 ObjectNotFoundException;
-
load 方法可返回没有加载实体数据的代理类实例,而 get 方法永远返回有实体数据的对象。
总之根本区别 hibernate 对于 load 方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,如果在使用过程中发现了问题,只能抛异常;而对于 get 方 法,hibernate 一定要获取到真实的数据,否则返回 null。
Hibernate 中怎样实现类之间的关系 ?(如:一对多、多对多的关系)
类与类之间的关系主要体现在表与表之间的关系进行操作,它们都是对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的 many-to-one、one-to-many、many-to-many。
Hibernate 与 Ibatis / MyBatis 的区别
Hibernate 是一个开放源代码的对象关系映射框架,它对 JDBC 进行了非常轻量级的对象封装,建立对象与数据库表的映射。是一个全自动的、完全面向对象的持久层框架。
Mybatis 是一个开源对象关系映射框架,原名:ibatis,2010年由谷歌接管以后更名。是一个半自动化的持久层框架。
两者区别
- 开发方面
在项目开发过程当中,就速度而言:hibernate 开发中,sql 语句已经被封装,直接可以使用,加快系统开发;Mybatis 属于半自动化,sql 需要手工完成,稍微繁琐;但是,凡事都不是绝对的,如果对于庞大复杂的系统项目来说,发杂语句较多,选择hibernate 就不是一个好方案。
- sql 优化方面
Hibernate 自动生成 sql,有些语句较为繁琐,会多消耗一些性能;Mybatis 手动编写 sql,可以避免不需要的查询,提高系统性能
- 对象管理
Hibernate 是完整的对象-关系映射的框架,开发工程中,无需过多关注底层实现,只要去管理对象即可;Mybatis 需要自行管理 映射关系
- 缓存方面
相同点:
Hibernate 和 Mybatis 的二级缓存除了采用系统默认的缓存机制外,都可以通过实现你自己的缓存或为其他第三方缓存方案,创建适配器来完全覆盖缓存行为。
不同点:
Hibernate 的二级缓存配置在 SessionFactory 生成的配置文件中进行详细配置,然后再在具体的表-对象映射中配置那种缓存。
MyBatis 的二级缓存配置都是在每个具体的表-对象映射中进行详细配置,这样针对不同的表可以自定义不同的缓存机制。并且 Mybatis 可以在命名空间中共享相同的缓存配置和实例,通过 Cache-ref 来实现。
比较
Hibernate 具有良好的管理机制,用户不需要关注 SQL,如果二级缓存出现脏数据,系统会保存;Mybatis 在使用的时候要谨慎,避免缓存 CAche 的使用。
Hibernate 优势
Hibernate 的 DAO 层开发比 MyBatis 简单,Mybatis 需要维护 SQL 和结果映射。
Hibernate 对对象的维护和缓存要比 MyBatis 好,对增删改查的对象的维护要方便。
Hibernate 数据库移植性很好,MyBatis 的数据库移植性不好,不同的数据库需要写不同 SQL。
Hibernate 有更好的二级缓存机制,可以使用第三方缓存。MyBatis 本身提供的缓存机制不佳。
Mybatis 优势
MyBatis 可以进行更为细致的 SQL 优化,可以减少查询字段。
MyBatis容易掌握,而Hibernate门槛较高。
一句话总结
Mybatis:小巧、方便、高效、简单、直接、半自动化
Hibernate:强大、方便、高效、复杂、间接、全自动化