Hibernate面试流程

      Hibernate面试流程 Gavin King
一.什么叫Hibernate ORM(Object relation mapping)对象、关系、映射
产生的原因:对象与数据库的不同步,面向对象与关系数据库存在的互不匹配的现象。

Hibernate 是一个面向Java 环境的对象/关系数据库映射工具。它对JDBC进行了非常轻量级的对象封装,使得Java程序员可以按对象编程思维来操纵数据库。
Hibernate也是目前Java开发中最为流行的数据库持久层框架,现已归JBOSS所有。

二:Hibernate的优缺点:
  1:优点:
1:Hibernate 使用 Java 反射机制 而不是字节码增强程序来实现透明性。
2:Hibernate 的性能非常好,映射比较灵活,开发随度快。
3:跨平台,支持各种关系数据库,从一对一到多对多的各种复杂关系。
  2:缺点:
1:Hibernate限制您所使用的对象模型。例如,一个持久性类不能映射到多个表。
2:SQL 自动生成,更改SQL语句影响性能,不好调试。
3:SQL语言透明,如更新字段 不能优化。

三.hibernate与ibatis比较.
(1):Ibatis:半自动,实体类和SQL语句,方便,进行细粒度的优化,要求开发者编写具体的SQL语句。标准SQL方便移植,如果用到具体的数据库sql则不方便移植。
(2):Hibernate: 全自动,实体类和数据库,1.一般情况下,hibernate会把所有的字段都select。2.update一般也是更新所有字段。HIBERNATE会自动生成SQL 语句,移植方便。

四:hibernate的映射机制:
关联映射:
一对一  主键关联,外键关联 
一对多  外键关联
多对多  外键关联
继承映射 主要有3种  分别是 joined-subclass   union-subclass   subclass
joined-subclass:每个类层次映射一个表
union-subclass:每个子类(具体类)映射一个表
subclass  所有类用一个表映射

一对一:
   父类:
@OneToOne(cascade=CascadeType.ALL)//级联增删除  修改
@PrimaryKeyJoinColumn//外键连接
子类:
// 主键生成方式   strategy 约束="生成机制"
@GenericGenerator(name="pkGenerator",strategy="foreign",
parameters={
@Parameter(name="property",value="parent")
})
@GeneratedValue(generator="pkGenerator")
private Long sid;

//级联操作:cascade = CascadeType.ALL  //映射:mappedBy = "子类"
@OneToOne(cascade=CascadeType.ALL,mappedBy="subclass")
@JoinColumn(name="sid")//连接的字段

一对多
父类:
@OneToMany(cascade = CascadeType.ALL, mappedBy = "classes", fetch = FetchType.LAZY)
子类:
//optional 可选的   = false 关联的
@ManyToOne(cascade = CascadeType.ALL, optional = false)
// 这里是告诉 cid 是在表里关联的字段             外键为cid,与Classes中的id关联
@JoinColumn(name = "cid", referencedColumnName = "id")

多对多:
父类:
// targetEntity=Role.class 目标实体
@ManyToMany(targetEntity = Role.class, cascade = { CascadeType.ALL })
// 中间表
// joinColumns={@JoinColumn(name="uid")}, 当前的主键 关联 USER_ROLE_TABLE 字段叫 uid
@JoinTable(name = "USER_ROLE_TABLE", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns = { @JoinColumn(name = "rid") })
子类:
因为在父类定义了中间表所以在这里就没有必要了。
// mappedBy = "roles", User类中Set  targetEntity 实体类
@ManyToMany(cascade = { CascadeType.ALL }, mappedBy = "roles", targetEntity = User.class)

五:在公司怎么用的:
一般来说在都使用注解,这样解决了以前 每个pojo就需要配置一个.hbm.xml 文件。
然而在.cfg.xml文件里session-factory中配置:
配置:<mapping resource=".hbm.xml  路径" />
注解:<mapping class="JavaBean路径" />
JavaBean
1.在class 上配置 @Entity 实体 @Table 对应数据库的某个表。
2.在get() 方法上 @Id 唯一 @Generatedvalue 主键 @Column 对应数据库的名称。
在Test  测试类中
注解: 
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
配置:
sessionFactory = new Configuration().configure().buildSessionFactory();
因为用到注解所用到的jar,不用注解则不要
ejb3-persistence-1.0.2.GA.jar
hibernate-annotations-3.4.0.GA.jar
hibernate-commons-annotations-3.1.0.GA.jar
slf4j-api-1.5.8.jar
slf4j-log4j12-1.5.8.jar

六:遇到的问题,有什么经验与教训:
在测试类的时候而报堆栈溢出的错,就是在调用toString()方法时候进了死循环。

解决的方法:
     以前只知道是因为toString() 方法的的问题,所有当时是不写toString()方法。
后来找到了真正解决的方法,在toString() 只不写集合对象的字段。

在Action尽量不要写get()方法,影响性能。Get()方法是往服务端传递数据的。
如果是我会用注解,但项目大的时候一个pojo就需要配置一个.hbm.xml 文件,占内存不说,在查看 维护时配置文件过多,不利于查看 维护。

七:Hibernate  POJO对象的三种状态:
Pojo
1.瞬态:对象刚创建出来的时候 没有被session管理就是瞬时状态,这时,无论发生什么操作都不会同步到数据库
2.持久:对象被Session管理,与数据库的数据相对应,这就是持久状态,它发生一系列操作,都会同步到数据库。
3.托管:曾经被持久化过,数据库中有数据与之对应,但当前没有session与之关联;脱管对象状态发生改变,hibernate不能检测到。

八Hibernate的主键生成机制
我常用的有以下几种 native  identity(一般我们都用的是这种自动增长)  uuid算法生成字符串类型的标识符。

九hibernate的几种查询方式
HQL   QBC  QBE  SQL
1:HQL功能最强大,适合各种情况,但是动态条件查询构造起来很不方便。
2:QBC最适合动态条件查询,不太适合统计查询。
    3:QBE还不够强大,只适合相当简单的查询。
4:SQL就是特定数据库的SQL 移植性就没有了。

十load()和get()的区别:
Get()它会马上去数据库拿取数据。
Load()他是从缓存中查找。当Lazy为true的时候 它不会去立即加载,而是调用到数据的时候再去加载。当Lazy为false他就会去立即加载。
Get()寻找数据找不到会返回一个Null。
Load()找不到数据的时候会抛出一个ObjectNotFound。

十一Query.list()和iterate()的区别:
1: 获取数据的方式不一样,当查询缓存不存在时,list()会直接查数据库返回结果集, iterate()会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存中找,如果找不到,以id为条件再发一条sql到数据库,这样如果缓存中没有数据,则查询数据库的次数为n+1。
2:query.list()用查询缓存,query.iterate不用。 
3: query.iterate利用一级缓存和二级缓存  而list会填充一级缓存和二级缓存 可以这么设想 如果都一次用list,之后用iterate,效果应比较好。

十二Hibenate为什么能跨平台
因为有方言,数据可必须有Dialect方言。
Dialect 方言定义了很多数据库,大多数数据库是一样
模版模式: 定义的都是数据库基本上有的类型。
Oracle在Hibernate 10i 比9i 多了一个joinFragment(),8i比9i就多了一个分页的方法,8i就直接继承Dialect。
在9i中getLimitString()分页方法,用到了适配器模式。用protected 修饰   巧妙 ,客户调用都是抛异常。

十三N+1
当一对多的时候,查询List  N条 数据加上本身一条就是N+1条。
主表 n 条记录,主表是1次,也是N次。
本身不会左联接、右连接。
当我们从数据库拿数据,怎么拿呢,在这边要拿N+1条数据,这样会导致数据库挂掉。
怎么样能解决这个问题:
懒加载或者抓载策略。

hibernate抓取的策略:
   连接抓取:
      fetch="join" 通过select语句使用外连接来加载其关联实体或集合 此时lazy会 失效。
查询抓取:
       fetch="select" 另外发送一条select语句抓取当前对象关联实体或集合 默认的。
   子查询抓取:
fetch="subselect" 另外发送一条select语句抓取在前面查询到的所有实体对象 的关联实体或集合 通过子查询in完成。
     批量抓取 :
         batch-size设置。

十四hibernate的核心类和接口.
1.Configuration: 负责管理Hibernate的配置信息,这些配置信息都是从配置文件hibernate.cfg.xml或者Hibernate.properties读取的,当然也可以自定义文件名称,只要在实例化Configuration的时候指定具体的路径就可以了。
2.SessionFactory: Configuration的实例会根据当前的配置信息,构造SessionFactory实例。SessionFactory是线程安全的,一般情况下,一个应用中一个数据库共享一个SessionFactory实例。
3.Session: 一般的持久化方法(ADQU)都是通过Session来调用的,Session是非线程安全的。
4.Transaction: 事务管理。
5.Query: 查询的接口。

十五Session的管理.
缓存 = = 以空间换取时间。
一级缓存:不用配置,自动。
二级缓存:缓存被应用范围内的所有事务共享。默认是二级缓存。
对大量查询的时候用到缓存。
1.作用: Session是Hibernate运作的中心,对象的生命周期、事务的管理、数据库的存取,都与Session息息相关,就如同在编写JDBC时需关心Connection的管理,以有效的方法创建、利用与回收Connection,以减少资源的消耗,增加系统执行效能一样,有效的管理Session,也是Hibernate应用时需关注的焦点。
2.特点: Session是由SessionFactory所创建,SessionFactory是线程安全的(Thread-Safe),您可以让多个线程同时存取SessionFactor而不会有数据共享的问题,然而Session则不是设计为线程安全的,所以试图让多个线程共享一个Session,将会发生数据共享而发生混乱的问题。在各种Session管理方案中,ThreadLocal模式得到了大量使用。ThreadLocal是Java中一种较为特殊的线程绑定机制。
3.如何解决session数据共享所带来的数据混乱问题?
答: 通过ThreadLocal对象,ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM为每个运行的线程绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。

十六hibernate性能优化方案.
1.数据库设计优化。
2.Hibernate的hql优化。
3.API的正确使用。
4.缓存的配置管理(如:二级缓存中使用的技术是:EhCascade)。
5.关闭hql的打印输出(在hibernate.cfg.xml中不使用show sql)。
6.ID生成策略,延迟加载,关联优化。

十七乐观锁和悲观锁.
悲观锁的实现:通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改,利用LockMode.UPGRADE。
乐观锁:大多数基于数据版本记录机制(version)实现,一般是在数据库表中加入一个version字段。读取数据时将版本号一同读出,之后更新数据时版本号加一,如果提交数据时版本号小于或等于数据表中的版本号,则认为数据是过期的,否则给予更新。
乐观锁的实现步骤:
<1.在class标签上使用optimistic-lock="version"属性。
如:<class name="com.Person" table="person" optimistic-lock="version">
<2.在id属性后增加 <version name="version"/>。
<3.给pojo类增加一个int类型version属性,增加set和get方法。
在所有源码中hibernate源码是最复杂的。
Eventsample 多对多
Org.hibernate.auction  Main.java  是hibernate 入口点

猜你喜欢

转载自lao-song.iteye.com/blog/1633281