两个蝴蝶飞 2012-08-15
Hibernate面试流程GavinKing
一.什么叫HibernateORM(Objectrelationmapping)对象、关系、映射
产生的原因:对象与数据库的不同步,面向对象与关系数据库存在的互不匹配的现象。
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-subclassunion-subclasssubclass
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")
privateLongsid;
//级联操作: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类中SettargetEntity实体类
@ManyToMany(cascade={CascadeType.ALL},mappedBy="roles",targetEntity=User.class)
五:在公司怎么用的:
一般来说在都使用注解,这样解决了以前每个pojo就需要配置一个.hbm.xml文件。
然而在.cfg.xml文件里session-factory中配置:
配置:<mappingresource=".hbm.xml路径"/>
注解:<mappingclass="JavaBean路径"/>
JavaBean
1.在class上配置@Entity实体@Table对应数据库的某个表。
2.在get()方法上@Id唯一@Generatedvalue主键@Column对应数据库的名称。
在Test测试类中
注解:
sessionFactory=newAnnotationConfiguration().configure().buildSessionFactory();
配置:
sessionFactory=newConfiguration().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文件,占内存不说,在查看维护时配置文件过多,不利于查看维护。
七:HibernatePOJO对象的三种状态:
Pojo
1.瞬态:对象刚创建出来的时候没有被session管理就是瞬时状态,这时,无论发生什么操作都不会同步到数据库
2.持久:对象被Session管理,与数据库的数据相对应,这就是持久状态,它发生一系列操作,都会同步到数据库。
3.托管:曾经被持久化过,数据库中有数据与之对应,但当前没有session与之关联;脱管对象状态发生改变,hibernate不能检测到。
八Hibernate的主键生成机制
我常用的有以下几种nativeidentity(一般我们都用的是这种自动增长)uuid算法生成字符串类型的标识符。
九hibernate的几种查询方式
HQLQBCQBESQL
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在Hibernate10i比9i多了一个joinFragment(),8i比9i就多了一个分页的方法,8i就直接继承Dialect。
在9i中getLimitString()分页方法,用到了适配器模式。用protected修饰巧妙,客户调用都是抛异常。
十三N+1
当一对多的时候,查询ListN条数据加上本身一条就是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中不使用showsql)。
6.ID生成策略,延迟加载,关联优化。
十七乐观锁和悲观锁.
悲观锁的实现:通常依赖于数据库机制,在整个过程中将数据锁定,其它任何用户都不能读取或修改,利用LockMode.UPGRADE。
乐观锁:大多数基于数据版本记录机制(version)实现,一般是在数据库表中加入一个version字段。读取数据时将版本号一同读出,之后更新数据时版本号加一,如果提交数据时版本号小于或等于数据表中的版本号,则认为数据是过期的,否则给予更新。
乐观锁的实现步骤:
<1.在class标签上使用optimistic-lock="version"属性。
如:<classname="com.Person"table="person"optimistic-lock="version">
<2.在id属性后增加<versionname="version"/>。
<3.给pojo类增加一个int类型version属性,增加set和get方法。
在所有源码中hibernate源码是最复杂的。
Eventsample多对多
Org.hibernate.auctionMain.java是hibernate入口点