Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言 Java 技术具有卓越的通用性高效性平台移植性和安全性, 广泛应用于 PC 数据中心游戏控制台科学超级计算机移动电话和互联网, 同时拥有全球最大的开发者专业社群 1 什么是 ORM?
答: 对象关系映射 (Object-Relational Mapping, 简称 ORM) 是一种为了解决程序的面向对象模型与数据库的关系模型互不匹配问题的技术; 简单的说, ORM 是通过使用描述对象和数据库之间映射的元数据(在 Java 中可以用 XML 或者是注解), 将程序中的对象自动持久化到关系数据库中或者将关系数据库表中的行转换成 Java 对象, 其本质上就是将数据从一种形式转换到另外一种形式
答: 所谓持久就是将数据保存到可掉电式存储设备中以便今后使用, 简单的说, 就是将内存中的数据保存到关系型数据库文件系统消息队列等提供持久化支持的设备中持久层就是系统中专注于实现数据持久化的相对独立的层面
持久层设计的目标包括:
- 数据存储逻辑的分离, 提供抽象化的数据访问接口
- 数据访问底层实现的分离, 可以在不修改代码的情况下切换底层实现
- 资源管理和调度的分离, 在数据访问层实现统一的资源调度(如缓存机制)
- 数据抽象, 提供更面向对象的数据操作小编推荐一个学 Java 的学习裙 六五零, 五五四, 六零七 , 无论你是大牛还是小白, 是想转行还是想入行都可以来了解一起进步一起学习! 裙内有开发工具, 很多干货和技术资料分享!
持久层框架有:
- - Hibernate
- - MyBatis
- - TopLink
- - Guzz
- - jOOQ
- - Spring Data
- - ActiveJDBC
3Hibernate 中 SessionFactory 是线程安全的吗? Session 是线程安全的吗(两个线程能够共享同一个 Session 吗)?
答: SessionFactory 对应 Hibernate 的一个数据存储的概念, 它是线程安全的, 可以被多个线程并发访问 SessionFactory 一般只会在启动的时候构建对于应用程序, 最好将 SessionFactory 通过单例模式进行封装以便于访问 Session 是一个轻量级非线程安全的对象 (线程间不能共享 session), 它表示与数据库进行交互的一个工作单元 Session 是由 SessionFactory 创建的, 在任务完成之后它会被关闭 Session 是持久层服务对外提供的主要接口 Session 会延迟获取数据库连接(也就是在需要的时候才会获取) 为了避免创建太多的 session, 可以使用 ThreadLocal 将 session 和当前线程绑定在一起, 这样可以让同一个线程获得的总是同一个 sessionHibernate 3 中 SessionFactory 的 getCurrentSession()方法就可以做到
4Hibernate 中 Session 的 load 和 get 方法的区别是什么?
答: 主要有以下三项区别:
如果没有找到符合条件的记录, get 方法返回 null,load 方法抛出异常
get 方法直接返回实体类对象, load 方法返回实体类对象的代理
在 Hibernate 3 之前, get 方法只在一级缓存中进行数据查找, 如果没有找到对应的数据则越过二级缓存, 直接发出 SQL 语句完成数据读取; load 方法则可以从二级缓存中获取数据; 从 Hibernate 3 开始, get 方法不再是对二级缓存只写不读, 它也是可以访问二级缓存的
说明: 对于 load()方法 Hibernate 认为该数据在数据库中一定存在可以放心的使用代理来实现延迟加载, 如果没有数据就抛出异常, 而通过 get()方法获取的数据可以不存在
5Session 的 save()update()merge()lock()saveOrUpdate()和 persist()方法分别是做什么的? 有什么区别?
答: Hibernate 的对象有三种状态: 瞬时态 (transient) 持久态 (persistent) 和游离态 (detached), 如第 135 题中的图所示瞬时态的实例可以通过调用 save()persist() 或者 saveOrUpdate()方法变成持久态; 游离态的实例可以通过调用 update()saveOrUpdate()lock()或者 replicate()变成持久态 save()和 persist()将会引发 SQL 的 INSERT 语句, 而 update()或 merge()会引发 UPDATE 语句 save()和 update()的区别在于一个是将瞬时态对象变成持久态, 一个是将游离态对象变为持久态 merge()方法可以完成 save()和 update()方法的功能, 它的意图是将新的状态合并到已有的持久化对象上或创建新的持久化对象对于 persist()方法, 按照官方文档的说明: persist()方法把一个瞬时态的实例持久化, 但是并不保证标识符被立刻填入到持久化实例中, 标识符的填入可能被推迟到 flush 的时间; persist()方法保证当它在一个事务外部被调用的时候并不触发一个 INSERT 语句, 当需要封装一个长会话流程的时候, persist()方法是很有必要的; save()方法不保证第条, 它要返回标识符, 所以它会立即执行 INSERT 语句, 不管是在事务内部还是外部至于 lock()方法和 update()方法的区别, update()方法是把一个已经更改过的脱管状态的对象变成持久状态; lock()方法是把一个没有更改过的脱管状态的对象变成持久状态
6 阐述 Session 加载实体对象的过程
答: Session 加载实体对象的步骤是:
Session 在调用数据库查询功能之前, 首先会在一级缓存中通过实体类型和主键进行查找, 如果一级缓存查找命中且数据状态合法, 则直接返回;
如果一级缓存没有命中, 接下来 Session 会在当前 NonExists 记录 (相当于一个查询黑名单, 如果出现重复的无效查询可以迅速做出判断, 从而提升性能) 中进行查找, 如果 NonExists 中存在同样的查询条件, 则返回 null;
如果一级缓存查询失败则查询二级缓存, 如果二级缓存命中则直接返回;
如果之前的查询都未命中, 则发出 SQL 语句, 如果查询未发现对应记录则将此次查询添加到 Session 的 NonExists 中加以记录, 并返回 null;
根据映射配置和 SQL 语句得到 ResultSet, 并创建对应的实体对象;
将对象纳入 Session(一级缓存)的管理;
如果有对应的拦截器, 则执行拦截器的 onLoad 方法;
如果开启并设置了要使用二级缓存, 则将数据对象纳入二级缓存;
返回数据对象
7Query 接口的 list 方法和 iterate 方法有什么区别?
答:
list()方法无法利用一级缓存和二级缓存 (对缓存只写不读), 它只能在开启查询缓存的前提下使用查询缓存; iterate() 方法可以充分利用缓存, 如果目标数据只读或者读取频繁, 使用 iterate()方法可以减少性能开销
list()方法不会引起 N+1 查询问题, 而 iterate()方法可能引起 N+1 查询问题
说明: 关于 N+1 查询问题, 可以参考 CSDN 上的一篇文章什么是 N+1 查询
8Hibernate 如何实现分页查询?
答: 通过 Hibernate 实现分页查询, 开发人员只需要提供 HQL 语句 (调用 Session 的 createQuery() 方法)或查询条件 (调用 Session 的 createCriteria() 方法)设置查询起始行数 (调用 Query 或 Criteria 接口的 setFirstResult() 方法)和最大查询行数 (调用 Query 或 Criteria 接口的 setMaxResults() 方法), 并调用 Query 或 Criteria 接口的 list()方法, Hibernate 会自动生成分页查询的 SQL 语句
9 锁机制有什么用? 简述 Hibernate 的悲观锁和乐观锁机制
答: 有些业务逻辑在执行过程中要求对数据进行排他性的访问, 于是需要通过一些机制保证在此过程中数据被锁住不会被外界修改, 这就是所谓的锁机制
Hibernate 支持悲观锁和乐观锁两种锁机制悲观锁, 顾名思义悲观的认为在数据处理过程中极有可能存在修改数据的并发事务 (包括本系统的其他事务或来自外部系统的事务), 于是将处理的数据设置为锁定状态悲观锁必须依赖数据库本身的锁机制才能真正保证数据访问的排他性, 关于数据库的锁机制和事务隔离级别在 Java 面试题大全(上) 中已经讨论过了乐观锁, 顾名思义, 对并发事务持乐观态度 (认为对数据的并发操作不会经常性的发生), 通过更加宽松的锁机制来解决由于悲观锁排他性的数据访问对系统性能造成的严重影响最常见的乐观锁是通过数据版本标识来实现的, 读取数据时获得数据的版本号, 更新数据时将此版本号加 1, 然后和数据库表对应记录的当前版本号进行比较, 如果提交的数据版本号大于数据库中此记录的当前版本号则更新数据, 否则认为是过期数据无法更新 Hibernate 中通过 Session 的 get() 和 load()方法从数据库中加载对象时可以通过参数指定使用悲观锁; 而乐观锁可以通过给实体类加整型的版本字段再通过 XML 或 @Version 注解进行配置
提示: 使用乐观锁会增加了一个版本字段, 很明显这需要额外的空间来存储这个版本字段, 浪费了空间, 但是乐观锁会让系统具有更好的并发性, 这是对时间的节省因此乐观锁也是典型的空间换时间的策略 135 阐述实体对象的三种状态以及转换关系
答: 最新的 Hibernate 文档中为 Hibernate 对象定义了四种状态 (原来是三种状态, 面试的时候基本上问的也是三种状态), 分别是: 瞬时态(new, or transient) 持久态 (managed, or persistent) 游状态 (detached) 和移除态(removed, 以前 Hibernate 文档中定义的三种状态中没有移除态), 如下图所示, 就以前的 Hibernate 文档中移除态被视为是瞬时态
10 阐述实体对象的三种状态以及转换关系
答: 最新的 Hibernate 文档中为 Hibernate 对象定义了四种状态 (原来是三种状态, 面试的时候基本上问的也是三种状态), 分别是: 瞬时态(new, or transient) 持久态 (managed, or persistent) 游状态 (detached) 和移除态(removed, 以前 Hibernate 文档中定义的三种状态中没有移除态), 如下图所示, 就以前的 Hibernate 文档中移除态被视为是瞬时态
小编推荐一个学 Java 的学习裙 六五零, 五五四, 六零七 , 无论你是大牛还是小白, 是想转行还是想入行都可以来了解一起进步一起学习! 裙内有开发工具, 很多干货和技术资料分享!
瞬时态: 当 new 一个实体对象后, 这个对象处于瞬时态, 即这个对象只是一个保存临时数据的内存区域, 如果没有变量引用这个对象, 则会被 JVM 的垃圾回收机制回收这个对象所保存的数据与数据库没有任何关系, 除非通过 Session 的 save()saveOrUpdate()persist()merge()方法把瞬时态对象与数据库关联, 并把数据插入或者更新到数据库, 这个对象才转换为持久态对象
持久态: 持久态对象的实例在数据库中有对应的记录, 并拥有一个持久化标识 (ID) 对持久态对象进行 delete 操作后, 数据库中对应的记录将被删除, 那么持久态对象与数据库记录不再存在对应关系, 持久态对象变成移除态 (可以视为瞬时态) 持久态对象被修改变更后, 不会马上同步到数据库, 直到数据库事务提交
游离态: 当 Session 进行了 close()clear()evict()或 flush()后, 实体对象从持久态变成游离态, 对象虽然拥有持久和与数据库对应记录一致的标识值, 但是因为对象已经从会话中清除掉, 对象不在持久化管理之内, 所以处于游离态 (也叫脱管态) 游离态的对象与临时状态对象是十分相似的, 只是它还含有持久化标识
提示: 关于这个问题, 在 Hibernate 的官方文档中有更为详细的解读
给你 Java 学习路线: html-CSS-js-jq-javase - 数据库 - jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
来源: http://www.jianshu.com/p/6c4e8e9014d8