1. 简述 hibernate 的开发流程
- 第一步:加载 hibernate 的配置文件,读取配置文件的参数(jdbc 连接参数,数据 库方言,hbm 表与对象关系映射文件)
- 第二步:创建 SessionFactory 会话工厂(内部有连接池)
- 第三步:打开 session 获取连接,构造 session 对象(一次会话维持一个数据连接,
也是一级缓存) - 第四步:开启事务
- 第五步:进行操作
- 第六步:提交事务
- 第七步:关闭 session(会话)将连接释放
- 第八步:关闭连接池
2. hibernate 中对象的三种状态
- 瞬时态(临时态、自由态):不存在持久化标识 OID,尚未与 Hibernate Session 关联对象, 被认为处于瞬时态,失去引用将被 JVM 回收
- 持久态:存在持久化标识 OID,与当前 session 有关联,并且相关联的 session 没有关闭 , 并且事务未提交
- 脱管态(离线态、游离态):存在持久化标识 OID,但没有与当前 session 关联,脱管状态 改变 hibernate 不能检测到
3. hibernate 的缓存机制。
- Hibernate 缓存分为两层:Hibernate 的一级缓存和 Hibernate 二级缓存。
###1. Hibernate 一级缓存(Session 的缓存):
- Session 实现了第一级 Cache,属于事务级数据缓冲。一旦事务结束,缓存随之失效。一个 Session 的生命周期对应一个数据库事务或一个程序事务。
- Session-Cache 总是被打开并且不能被关闭的。
- Session-Cache 保证一个 Session 中两次请求同一个对象时,取得的对象是同一个 Java 实例,有时它可以避免不必要的数据冲突。
- 在对于同一个对象进行循环引用时,不至于产生堆栈溢出。
- 当数据库事务结束时,对于同一数据表行,不会产生数据冲突。因为对于数据库中的一行,最多有一个对象来表示它。
- 一个事务中可能会有很多个处理单元,在每一个处理单元中做的操作都会立即被其他的数据单元得知。
2. Hibernate 二级缓存(SessionFactory 的缓存):
- 二级缓存是 SessionFactory 范围内的缓存,所有 Session 共享同一二级缓存。在二级缓存中保存持久化实例的散装形式的数据。
- 持久化不同的数据需不同的 Cache 策略,如一些因素将影响 Cache 策略的选择:数据的读/写比例、数据表是否能被其他的应用程序所访问等。
- 设置 Hibernate 二级缓存需要分两步:首先,确认使用什么数据并发策略。然后,配置缓存过期时间并设置 Cache提供器。
#4. 主要三种查询: HQL, QBC(命名查询), 以及使用原生 SQL 查询(SqlQuery)
参看:https://blog.csdn.net/q547550831/article/details/53326110
####1. OID查询:它就是根据id查询一个实体
- 涉及的方法:
get(Class clazz,Serializable id):参数1是要查询的实体字节码,参数2:是要查询的id。
load(Class clazz,Serializable id):参数1是要查询的实体字节码,参数2:是要查询的id。 - Hibernate的检索策略
- 类级别检索策略:
- get方法:
它永远都是立即加载。返回的对象是实体类类型。
立即加载的含义:不管用不用,都马上发起查询。 - load方法:
它默认是延迟加载。返回的是实体类对象的代理对象。
它可以通过配置的方式改为立即加载。配置的位置是映射文件的class标签。
涉及的属性是:lazy。含义就是是否延迟加载。 取值true延迟加载(默认值) false不是延迟加载
延迟加载的含义:什么时候用,什么时候真正发起查询。
- get方法:
- 类级别检索策略:
2. HQL查询(常用)
- HQL (Hibernate Query Language ) 是面向对象的查询语言,和 SQL相似 ,但它使用的是类、对象和属性的概念 ,而没表和字段的概念 。
- 涉及的对象:
Query - 如何获取Query:
session.createQuery(String hql); - HQL语句写法:
表名用实体类名称替代
字段名用实体类属性名称(get/set方法后面的部分,并且把首字母转小写)
- 涉及的对象:
3.SQL查询
5. Hibernate 和 Mybatis 的区别
- 相同点:
- 都可通过 SessionFactoryBuider 由 XML 配置文件生成 SessionFactory,然后由SessionFactory 生成 Session,最后 Session 来开启执行事务和 SQL 语句。其中 SessionFactoryBuider,SessionFactory,Session 的生命周期都是差不多的。
- Hibernate 和 MyBatis 都支持 JDBC 和 JTA 事务处理。
- Mybatis 优势:
- MyBatis 可以进行更为细致的 SQL 优化,可以减少查询字段。
- MyBatis 容易掌握,而 Hibernate 门槛较高。
- Hibernate 优势:
- DAO 层开发比 MyBatis 简单,Mybatis 需要维护 SQL 和结果映射。
- 对对象的维护和缓存要比 MyBatis 好,对增删改查的对象的维护要方便。
- 数据库移植性很好,MyBatis 的数据库移植性不好,不同的数据库需要写不同 SQL。
- Hibernate有更好的二级缓存机制,可使用第三方缓存。MyBatis 本身提供的缓存机制不佳。
6. Hibernate 和 JDBC 优缺点对比
- 相同点:
- 两者都是 java 数据库操作的中间件、
- 两者对数据库进行直接操作的对象都是线程不安全的,都需要及时关闭。
- 两者都可对数据库的更新操作进行显式的事务处理。
- 不同点:
- JDBC 是 SUN公司提供一套操作数据库的规范,用java代码操作数据库。Hibernate是基于 jdbc 的主流持久化框架, JDBC 访问数据库的代码做了封装。
- 使用的 SQL 语言不同:JDBC 使用基于关系型数据库的标准 SQL 语言,Hibernate 使用的是 HQL(Hibernatequery language)语言。
- 操作对象不同:JDBC 操作数据,将数据通过 SQL 语句直接传送到数据库中执行,Hibernate 操作持久化对象,由底层持久化对象的数据更新到数据库中。
- 数据状态不同:JDBC 操作的数据是“瞬时”的,变量值无法与数据库中的值保持一致; Hibernate操作的数据是可持久的,持久化对象的数据属性的值可跟数据库中的值保持一致。
7. Hibernate的orm 思想
ORM 指对象关系型映射(Object RelationShip Mapping )
就是通过创建实体类对象和数据库中的表关系进行一一对应,来实现通过操作实体类对象来更改数据库里边的数据信息。这里边起到关键作用的是通过
Hibernate 的映射文件+Hibernate 的核心配置文件。
8. get 和 load
- get 是立即加载,load 是延时加载。
- get 会先查一级缓存,再查二级缓存,然后查数据库;load 会先查一级缓存,如果没有找到,就创建代理对象,等需要的时候去查询二级缓存和数据库。( 延迟加载的特性)
- get 如果没有找到会返回 null,load 如果没有找到会抛出异常。
- 使用 session.load()方法来加载一对象时,并不会发出 sql 语句,得到的对象是代理对象,只保存实体对象id值,使用这对象得到其它属性时,才发出 sql 语句,从数据库中去查询对象;
- 相对于 load 的延迟加载方式,get 就直接的多,当使用session.get()方法来得到一个对象时,不管使不使用对象,都会发出 sql 语句去从数据库中查询出来。
9. Hibernate 的优化
- 数据库设计调整。
- HQL 优化。
- API 的正确使用(如根据不同的业务类型选用不同的集合及查询 API)。
- 主配置参数(日志,查询缓存,fetch_size, batch_size 等)。
- 映射文件优化(ID 生成策略,二级缓存,延迟加载,关联优化)。
- 一级缓存的管理。
- 针对二级缓存,还有许多特有的策略。
- 事务控制策略。
10. Hibernate 延迟加载?
- 为避免一些无谓的性能开销,当真需要数据时,才执行数据加载操作。Hibernate 中提供了对实体对象的延迟加载以及对集合的延迟加载,Hibernate3还提供了对属性的延迟加载。
- 过程:通过代理(Proxy)机制实现延迟加载。Hibernate 从数据库获取某一个对象数据、某一对象的集合属性值,某一对象所关联的另一个对象时,由于没有使用该对象的数据(除标识符外),并不从数据库加载真正的数据,只为该对象创建代理对象代表这个对象,这个对象上的所有属性都为默认值;只有在真正需要使用该对象的数据时才创建这个真正的对象,从数据库中加载它的数据。
11. No Session 问题
- 字面上的意思,是指代理不能被初始化,session 已经关闭。
- 原因:当执行 Session 的 load()方法时,Hibernate 不会立即执行查询所查询对象关联的对象(在此我们统称被关联的对象类为 A 类),仅返回 A 类的代理类的实例,这个代理类具由以下特征:
- 扩展了 A 类继承了 A 类的所有属性和方法,但它的实现对于应用程序是透明的。
- 当创建 A 类代理类实例时,仅初始化了它的OID 属性,其他属性都为null,因此这个代理类实例占用的内存很少。
- 当应用程序第一次访问 A 代理类实例时(如调用 a…getXXX()或 a.setXXX()方法),会初始化代理类实例,初始化过程中执行 select 语句,真正从数据库中加载 A 对象的所有数据。但有例外,当程序访问 A 代理类实例的 getId()方法时,不会初始化代理类实例,因创建代理类实例时OID就存在了,不必到数据库中去查询。
- 提示:Hibernate 采用 CGLIB 工具来生成持久化类的代理类。CGLIB 是个强大的 Java 字节码生成工具,能在程序运行时动态生成扩展 Java 类或者实现 Java 接口的代理类。
- 因Hibernate 中如采用 load 加载(默认延迟加载) lazy=true 操作,调用完 load后,session 即可关闭。因 session 只是放置到了 Dao 层,表现层获取不到,所以在表现层调用的时候,session 已经关闭,报错。
12. Spring 的两种代理 JDK 和 CGLIB 的区别浅谈
- Java 动态代理利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用 InvokeHandler 来处理。而 cglib 动态代理是利用 asm 开源包,对代理对象类的 class 文件加载进来,通过修改其字节码生成子类来处理。
- 如目标对象实现了接口,默认情况会采用 JDK 的动态代理实现 AOP
- 如目标对象实现了接口,可强制使用 CGLIB 实现 AOP
- 如目标对象没实现接口,必须采用 CGLIB 库,spring会自动在JDK动态代理和CGLIB间转换
13. Session 的缓存的作用
- 减少访问数据库的频率。程序从内存中读取持久化对象的速度比到数据库中查询数据的速度快多了,因此 Session 的缓存可提高数据访问的性能。
- 保证缓存中的对象与数据库中的相关记录保持同步。当缓存中持久化对象的状态发生了变换,Session 并不会立即执行相关的 SQL 语句,使得 Session 能够把几条相关的 SQL 语句合并为一条 SQL 语句,减少访问数据库次数,提高程序性能。
14. Session 的清理和清空
- Session 清理缓存是指按照缓存中对象的状态的变化来同步更新数据库;清空是 Session 的关闭;
15. Session 的特点
- 线程不安全,在设计软件架构时,应避免多个线程共享同一个 Session 实例。
- Session实例是轻量级的,指它的创建和销毁不需消耗太多资源。意味着在程序中可经常创建销毁 Session 对象,如为每个客户请求分配单独的 Session 实例,或为每个工作单元分配单独Session实例。
- 在 Session 中,每个数据库操作都是在一个事务(transaction)中进行的,可以隔离开不同的操作(甚至包括只读操作)。
16. Hibernate 三种检索策略的优缺点
###1. 立即检索
- 优点:对程序完全透明,不管对象处于持久化还是游离状态,程序都可以方便的从一个对象导航到与它关联的对象;
- 缺点:select 语句太多;可能会加载程序不需访问的对象浪费内存空间;
###2. 延迟检索 - 优点:由程序决定需加载哪些对象,可避免执行多余select 语句,避免加载程序不需访问的对象。提高检索性能,节省内存空间;
- 缺点:程序如希望访问游离状态代理类实例,须保证它在持久化状态时已经被初始化;
###3. 迫切左外连接检索 - 优点:对程序完全透明,不管对象处于持久化、游离状态,都可方便地从一个对象导航到与它关联的对象;使用了外连接,select 语句少;
- 缺点:可能会加载不需访问的对象,浪费内存空间;复杂的数据库表连接影响检索性能;