1、Hibernate 知识大合集一 简答题1 请说出 Hibernate 中持久化对象的生命周期以及各种状态直接的区别,并描述相互之间是如何转换的。Hibernate 中持久化对象的生命周期有临时态、持久态和游离态三种。处于临时态的对象主键值为空,并且未与 session 关联,数据未保存到数据库中处于持久态的对象与 session 关联起来,持久化后对象中的数据被保存到数据库中,并且主键值按照.hbm.xml 文件中配置的生成方式生成相应的值处于游离态的对象脱离了 session 的管理,是持久化后的一种状态,主键值按照.hbm.xml 文件中配置的生成方式生成相应的值当 new 一个新的对象
2、时,该对象处于临时态当该对象被当作 session 的参数使用的时候,该对象处于持久态事务提交,session 关闭后,该对象处于游离态2hibernate 与数据库连接的实现?并解释了一下,例如文件是通过流来实现的!hibernate 与数据库连接是通过什么实现的?Hibernate 与数据库的连接是通过 JDBC 实现的3spring 和 hibernate 的事务管理方式有什么不同?hibernate 的事务管理方式仅仅就是托管给 JDBC(如果用 JTA 那么就是 JTA) ,而 JDBC 的一切行为包括事务是基于一个 connection 的,那么 hibernate 委托给 JDB
3、C 的事务也就是基于一个 session。JTA与 JDBC 事务不同在于可以跨连接。spring 也是调用 hibernate 中事务管理的 API。hibernate 的事务管理,一般是编程性的。而委托给 spring 之后,可以使用声明式的,也就是可以在 XML 之中配置哪些需要进行事务管理,哪些不需要4用 hibernate 的 session 时要注意几点1.在更新数据时,要用 open()2.使用完之后,要 close(),这样连接池会回收该连接。5说说在 hibernate 中使用 Integer 做映射和使用 int 做映射之间有什么差别使用 int 做映射,hibernate
4、 会自动把 int 类型转换为 Integer 类型,以便统一以对象方式处理数据。使用 Integer 就无须转换。在从数据库中取数据的时候,如果是用 Integer 做的映射,则要求PO 对象中对应的类型也必须为 Integer 类型,使用的时候需要转换为 int。如果是 int 型,则无须转换。6一个网站应用,请设计一个持久化类 User,他可能有多张会员卡号、需要多个 email 地址(数量不定)作为其身份验证的方式设计三个类。User 类、会员卡类和 email 类。User 类与会员卡类和email 类之间是一对多的关系7请简单评价该设计的优劣:身份证号码作为一个 person 表的
5、主键一个表的主键值设计最好不要采用具有业务含义的字段。理由有二:1具有业务含义的字段的长度不固定2具有业务含义的字段的取值范围不定。可能是纯数字,也可能是纯字符,或者是数字和字符的混合情况。上述两个方面一但发生变动将不利于业务层的处理。8Hibernate 如何获取指定主键 id 的某对象,请举例,并进行可能的优劣比较三种方式:get(),load()和 find()Get()和 load()是先在缓存中查找对象,如果找不到再去数据库中查询;Find()是无论何时都在数据库中查询对象。三者比较起来 Get()和 load()的性能稍好一点。二问答题1请说出 Hibernate 中的映射关系有几
6、种,分别是什么,如何配置Hibernate 中的映射关系有一对一、一对多、多对多三种。一对一关系比较简单,只需在主控方(由谁想得到谁,前者即是主控方)定义。配置如下:简单模式:完整模式:解释:属性 描述 类型 必须name 与 PO 中对应的和主控方有一对一关联的属性名称,必须一致TEXT Nclass 与 PO 中对应的和主控方有一对一关联的属性类型,要求必须写出完整全类路径 TEXT Ncascade 针对被控方操作的级联关系,由主控方触发。它指的是当主控方执行操作时,被控方是否执行同一操作。可选值:All:所有情况下均触发级联操作None:与 All 相反Save-update:在执行
7、save-update 时进行级联操作Delete:在执行 delete 时进行级联操作 TEXT Nouter-join 是否使用外连接:True:总是使用外连接False:与 true 相反Auto(默认):如果被动方没有采用代理机制,则使用外连接BOOL Nconstrained 约束。它表示主控方表的主键上是否存在被控方的外键对其进行约束。它决定了 save、delete 等方法的级联操作顺序TEXT Nproperty-ref 被控类中用于和主控类相关联的属性名称。默认为关联类的主键属性名称。一般我们通过主键建立一对一的关联,所以采用默认值即可。如果一对一的关联并非建立在主键之间,则
8、可通过此参数指定关联属性 TEXT Naccess 属性值的读取方式:Field:通过 java 反射机制来访问实体的属性Property(默认):通过 getter()和 setter()方法访问实体的属性ClassName:指定实现net.sf.hibernate.property.PropertyAccessor 接口的全路径类名,通过该类中指定的方式访问实体属性 TEXT N一对多关系分为单向一对多关系和双向一对多关系。单向一对多关系只需在“一”方进行配置,双向一对多需要在关联双方均加以配置。配置如下:单向一对多:双向一对多:一的一方:多的一方:被动方的记录由 Hibernate 负责
9、读取,之后存放在主控方指定的Collection 类型属性中。解释:属性 描述 类型 必须name 与 PO 中对应的和主控方有一对多关联的集合属性名称,必须一致 TEXT Ycolumn 关联字段名 TEXT Yclass 一的一方的全路径类名 TEXT Ncascade 针对被控方操作的级联关系,由主控方触发。它指的是当主控方执行操作时,被控方是否执行同一操作。可选值:All:所有情况下均触发级联操作None:与 All 相反Save-update:在执行 save-update 时进行级联操作Delete:在执行 delete 时进行级联操作 TEXT Nupdate 是否对关联字段进行
10、 update 操作。默认为 trueBOOL Ninsert 是否对关联字段进行 insert 操作。默认为 trueBOOL NOuter-join 是否使用外连接:True:总是使用外连接False:与 true 相反Auto(默认):如果被动方没有采用代理机制,则使用外连接TEXT NProperty-ref 被控类中用于和主控类相关联的属性名称。默认为关联类的主键属性名称。一般我们通过主键建立一对一的关联,所以采用默认值即可。如果一对一的关联并非建立在主键之间,则可通过此参数指定关联属性 TEXT Naccess 属性值的读取方式:Field:通过 java 反射机制来访问实体的属性
11、Property(默认):通过 getter()和 setter()方法访问实体的属性ClassName:指定实现net.sf.hibernate.property.PropertyAccessor 接口的全路径类名,通过该类中指定的方式访问实体属性 TEXT N多对多关联:由于多对多关联的性能不佳,在设计中应避免大量使用。应根据情况,采取延迟加载机制来避免无谓的性能开销。配置如下:解释:属性 描述 类型 必须column 中间表映射中,关联方在中间表的关联字段 TEXT Yclass 关联放的类全路径名称 TEXT YOuter-join 是否使用外连接:True:总是使用外连接False:
12、与 true 相反Auto(默认):如果被动方没有采用代理机制,则使用外连接TEXT N2 请描述对象建模时的继承关系在 Hibernate 中有几种映射方式,如何映射一共有三种:每颗类继承树使用一张表,配置如下:三个类对应的字段都在一个数据表里表示。subtype 字段标识存储的是哪个子类,与 xml 文件中的对应。每个子类各一张表,配置如下:每个具体类各一张表,配置如下:3 请描述 Hibernate 中的缓存机制缓存是介于应用程序和物理数据源之间,其作用是为了降低应用程序对物理数据源访问的频次,从而提高了应用的运行性能。缓存内的数据是对物理数据源中的数据的复制,应用程序在运行时从缓存读写
13、数据,在特定的时刻或事件会同步缓存和物理数据源的数据。 缓存的介质一般是内存,所以读写速度很快。但如果缓存中存放的数据量非常大时,也会用硬盘作为缓存介质。缓存的实现不仅仅要考虑存储的介质,还要考虑到管理缓存的并发访问和缓存数据的生命周期。Hibernate 的缓存包括 Session 的缓存和 SessionFactory 的缓存,其中 SessionFactory 的缓存又可以分为两类:内置缓存和外置缓存。Session 的缓存是内置的,不能被卸载,也被称为 Hibernate 的第一级缓存。Session 的缓存是指 Session 的一些集合属性包含的数据。SessionFactory
14、的内置缓存中存放了映射元数据和预定义 SQL语句,映射元数据是映射文件中数据的拷贝,而预定义 SQL 语句是在 Hibernate 初始化阶段根据映射元数据推导出来,SessionFactory 的内置缓存是只读的,应用程序不能修改缓存中的映射元数据和预定义 SQL 语句,因此 SessionFactory 不需要进行内置缓存与映射文件的同步。SessionFactory 的外置缓存是一个可配置的插件。在默认情况下,SessionFactory 不会启用这个插件。外置缓存的数据是数据库数据的拷贝,外置缓存的介质可以是内存或者硬盘。SessionFactory 的外置缓存也被称为 Hiberna
15、te 的第二级缓存。Hibernate 的这两级缓存都位于持久化层,存放的都是数据库数据的拷贝,那么它们之间的区别是什么呢?为了理解二者的区别,需要深入理解持久化层的缓存的两个特性:缓存的范围和缓存的并发访问策略。持久化层的缓存的范围缓存的范围决定了缓存的生命周期以及可以被谁访问。缓存的范围分为三类。1 事务范围:缓存只能被当前事务访问。缓存的生命周期依赖于事务的生命周期,当事务结束时,缓存也就结束生命周期。在此范围下,缓存的介质是内存。事务可以是数据库事务或者应用事务,每个事务都有独自的缓存,缓存内的数据通常采用相互关联的的对象形式。2 进程范围:缓存被进程内的所有事务共享。这些事务有可能是
16、并发访问缓存,因此必须对缓存采取必要的事务隔离机制。缓存的生命周期依赖于进程的生命周期,进程结束时,缓存也就结束了生命周期。进程范围的缓存可能会存放大量的数据,所以存放的介质可以是内存或硬盘。缓存内的数据既可以是相互关联的对象形式也可以是对象的松散数据形式。松散的对象数据形式有点类似于对象的序列化数据,但是对象分解为松散的算法比对象序列化的算法要求更快。3 集群范围:在集群环境中,缓存被一个机器或者多个机器的进程共享。缓存中的数据被复制到集群环境中的每个进程节点,进程间通过远程通信来保证缓存中的数据的一致性,缓存中的数据通常采用对象的松散数据形式。对大多数应用来说,应该慎重地考虑是否需要使用集
17、群范围的缓存,因为访问的速度不一定会比直接访问数据库数据的速度快多少。持久化层可以提供多种范围的缓存。如果在事务范围的缓存中没有查到相应的数据,还可以到进程范围或集群范围的缓存内查询,如果还是没有查到,那么只有到数据库中查询。事务范围的缓存是持久化层的第一级缓存,通常它是必需的;进程范围或集群范围的缓存是持久化层的第二级缓存,通常是可选的。持久化层的缓存的并发访问策略当多个并发的事务同时访问持久化层的缓存的相同数据时,会引起并发问题,必须采用必要的事务隔离措施。在进程范围或集群范围的缓存,即第二级缓存,会出现并发问题。因此可以设定以下四种类型的并发访问策略,每一种策略对应一种事务隔离级别。事务
18、型:仅仅在受管理环境中适用。它提供了 Repeatable Read 事务隔离级别。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读和不可重复读这类的并发问题。读写型:提供了 Read Committed 事务隔离级别。仅仅在非集群的环境中适用。对于经常被读但很少修改的数据,可以采用这种隔离类型,因为它可以防止脏读这类的并发问题。非严格读写型:不保证缓存与数据库中数据的一致性。如果存在两个事务同时访问缓存中相同数据的可能,必须为该数据配置一个很短的数据过期时间,从而尽量避免脏读。对于极少被修改,并且允许偶尔脏读的数据,可以采用这种并发访问策略。只读型:对于从来不会修改的数
19、据,如参考数据,可以使用这种并发访问策略。事务型并发访问策略是事务隔离级别最高,只读型的隔离级别最低。事务隔离级别越高,并发性能就越低。什么样的数据适合存放到第二级缓存中?1、很少被修改的数据 2、不是很重要的数据,允许出现偶尔并发的数据3、不会被并发访问的数据4、参考数据不适合存放到第二级缓存的数据?1、经常被修改的数据2、财务数据,绝对不允许出现并发3、与其他应用共享的数据。Hibernate 的二级缓存如前所述,Hibernate 提供了两级缓存,第一级是 Session 的缓存。由于 Session 对象的生命周期通常对应一个数据库事务或者一个应用事务,因此它的缓存是事务范围的缓存。第
20、一级缓存是必需的,不允许而且事实上也无法卸除。在第一级缓存中,持久化类的每个实例都具有唯一的 OID。第二级缓存是一个可插拔的的缓存插件,它是由 SessionFactory 负责管理。由于 SessionFactory 对象的生命周期和应用程序的整个过程对应,因此第二级缓存是进程范围或者集群范围的缓存。这个缓存中存放的对象的松散数据。第二级对象有可能出现并发问题,因此需要采用适当的并发访问策略,该策略为被缓存的数据提供了事务隔离级别。缓存适配器用于把具体的缓存实现软件与 Hibernate集成。第二级缓存是可选的,可以在每个类或每个集合的粒度上配置第二级缓存。Hibernate 的二级缓存策
21、略的一般过程如下:1) 条件查询的时候,总是发出一条 select * from table_name where . (选择所有字段)这样的 SQL 语句查询数据库,一次获得所有的数据对象。 2) 把获得的所有数据对象根据 ID 放入到第二级缓存中。 3) 当 Hibernate 根据 ID 访问数据对象的时候,首先从 Session 一级缓存中查;查不到,如果配置了二级缓存,那么从二级缓存中查;查不到,再查询数据库,把结果按照 ID 放入到缓存。 4) 删除、更新、增加数据的时候,同时更新缓存。Hibernate 的二级缓存策略,是针对于 ID 查询的缓存策略,对于条件查询则毫无作用。为此
22、,Hibernate 提供了针对条件查询的 Query缓存。Hibernate 的 Query 缓存策略的过程如下: 1) Hibernate 首先根据这些信息组成一个 Query Key,Query Key包括条件查询的请求一般信息:SQL, SQL 需要的参数,记录范围(起始位置 rowStart,最大记录个数 maxRows),等。 2) Hibernate 根据这个 Query Key 到 Query 缓存中查找对应的结果列表。如果存在,那么返回这个结果列表;如果不存在,查询数据库,获取结果列表,把整个结果列表根据 Query Key 放入到 Query缓存中。 3) Query Ke
23、y 中的 SQL 涉及到一些表名,如果这些表的任何数据发生修改、删除、增加等操作,这些相关的 Query Key 都要从缓存中清空。三程序分析1一个 WEB 程序,首先,页面注册一个用户比如用户名 aa 密码 aa。注册完以后,查看数据库,数据插入到了数据库中,然后重开个页面,登录,输入用户名 aa 密码 aa,无法登录,说是找不到。其调用的方法是 getUserByNameAndPassword(用户名,密码)。此时服务器不关,直接执行 JUnit 的测试文件,调用该方法,能找到这个用户的注册信息, ,然后服务器重启,此时再输入用户名 aa 密码 aa,便能登录了,请问下,在不看代码的情况下
24、,可能是什么地方出了问题?插入及访问代码是基于 Hibernate 编写的,要求写出可能的情况及解决方案第一种方案:应该是 hibernate 缓存的问题.在注册完以后只是把数据保存在了缓存里面,而没有提交到数据库.当你用 Junit 测试的时候当然可以测成功,因为 hibernate 是先查看缓存的.如果缓存里面有它想要的东西就不查数据库了,直接拿过来用.如果没有才查的.至于说关闭服务器以后,重起就可以登陆了.那应该是在关闭服务器的同时,hibernate commit 了缓存里面的数据.第二种方案:getUserByNameAndPassword(用户名,密码)方法得不到用户很可能是 hi
25、bernate 的缓存机制没有控制好,导致该方法读取用户验证时并不是从数据库读取,而是从 hibernate 的 session 中读取,session 由于还是原先没插值前的缓存,所以得不到用户。有 2 中解决方法:1.在 getUserByNameAndPassword(用户名,密码)方法中加上 HibernateSessionFactory.getSession().clear();2.在 session.save()方法里面(也就是 insert)在插入了注册的用户信息,事务提交后,调用 session.close()方法将 session 关闭。第三种方案:在 hibernate 进
26、行 save 操作的时候,它会将 save 的这条数据同时缓存进 session 和 sessionFactory(如果有配二级缓存的话) 。当下次来查询的时候,Hibernate 会先从查询sessionFactory,如果没有查到,继续查询 session,如果还是没有查询到,就查询数据库。但现在的现象好像是,hibernate 查询了 session 没有查到之后,就没有继续进行查询了,而是就返回结果了。find 操作和 save 操作应该是不会共享 session 的,因为session 是非线程安全的。可能是在二级缓存的时候出了问题,在二级缓存中好像有一个类似“黑名单”的东西,里面保
27、存了没有记录的查询语句,当 hibernate 发行这条查询语句在这个“黑名单”中的时候,它就不会继续查询数据库了,而是直接返回没有找到数据。第四种方案:其实这个应该是缓存问题的一种错误使用方式造成的。他应该是在 getUserByNameAndPassword 里用的 get()或者 load()这种方法去获取的数据。这 2 种方法都是从缓存里去读取数据。只有find()是直接从数据库拿数据。而他的数据库的连接方式可能是注册时开启了一个连接,之后并未马上关闭,之后登陆时用的同一个连接,所以是不会从数据库拿数据的。重起服务器之后,是因为连接里的数据更新了,所以是可以得到数据的。解决方式可以有好
28、几种了。将获得数据改成每次都从数据库拿的方式,或者是上面说的将 session 里的流清空掉,还可以再开起一个连接。你可以根据需要来决定。至于配置,可以不需要做高级的属性设置的。补充一下,Junit 测试是因为它每次连接都是新的。第五种方案:它应该是启用了 hibernate 二级缓存,而且还使用了查询缓存,在它的 createQuery(“from User u where u.userName=? and password=? “)语句后面恐怕还有setCacheable(true)这样的语句,并且在你创建该用户前肯定用该用户和密码登录过,此时肯定登录不了,查询返回的结果是 null,但是
29、已经把该查询和结果缓存到二级查询缓存中去了,当你创建该用户后,不重起登录,该查询取的是查询缓存中的结果,即 null,所以登录不了。而在 JUnit 测试中,肯定有开关,不使用二级查询缓存,即不执行 setCacheable(true),这样就直接查数据库,就能查到了。2指出一下代码哪里错误使用了 Hibernate。背景简介:Board 是一个实体类,id 是它的主键,name 和 description 是他的两个属性。BoardDao 是 Board 实体的数据访问对象,BoardBo 是业务对象,用户提交变更 Board 对象的请求,由 Struts 的 BoardAction 接收,
30、调用 BoardBo 处理。HibernateUtil.currentSession()用于返回当前请求的 Session 对象。 代码1. /数据访问层代码:BoardDao.java 2. public Board loadBoard(Long id) 3. Session session = HibernateUtil.currentSession(); 4. return session.load(Board.class, id); 5. 6. public void updateBoard(Board board) 7. Session session = HibernateUtil
31、.currentSession(); 8. session.update(board); 9. 10. 11. /业务对象层代码:BoardBo.java 12. private BoardDao boardDao; 13. public void updateBoard(Long id, String name, String description) 14. Board board = boardDao.loadBoard(id); 15. board.setName(name); 16. board.setDescription(description); 17. boardDao.up
32、dateBoard(board); 18. 19. 20. /Web 控制器代码:BoardAction.java 21. private BoardBo BoardBo; 22. public ActionForward execute( 23. ActionMapping mapping, 24. ActionForm form, 25. HttpServletRequest request, 26. HttpServletResponse response) throws Exception 27. String id = request.getParameter(“id“); 28.
33、String name = request.getParameter(“name“); 29. String description = request.getParameter(“description“); 30. boardBo.updateBoard(id, name, description); 31. return mapping.findForward(“update-success“); 32. 1第 30 行 boardBo.updateBoard(id, name, description)没有对id 进行类型转换。接收时为 String,调用 updateBoard 时需
34、要的是Long 型。2持久层的操作没有关闭 session 的代码,并且在 update 之后没有 commit();四判断题1使用 save 方法 persist 一个对象时,便立即向数据库发送执行insert sql 语句?不会。先保存在 session 缓存中。待 commit()之后才向数据库发送insert sql 语句=5.Hibernate 有哪几种查询数据的方式 hql 查询,sql 查询,条件查询6.load()和 get()的区别 hibernate 对于 load 方法认为该数据在数据库中一定存在,可以放心的使用代理来延迟加载,load 默认支持延迟加载,在用到对象中的其
35、他属性数 据时才查询数据库,但是万一数据库中不存在该记录,只能抛异常 ObjectNotFoundEcception;所说的 load 方法抛异常是指在使用该对 象的数据时,数据库中不存在该数据时抛异常,而不是在创建这个对象时。由于 session 中的缓存对于 hibernate 来说是个相当廉价的资源,所以在 load 时会先查一下 session 缓存看看该 id 对应的对象是否存在,不存在则创建代理(load 时候之查询一级缓存,不存在则创建代理) 。get() 现在一级缓存找,没有就去二级缓存找,没有就去数据库找,没有就返回 null ;而对于 get方法,hibernate 一定要
36、获取到真实的数据,否则返回 null。7.谈谈 hibernate 的延迟加载和 openSessionInView 延迟加载要在 session 范围内,用到的时候再加载;opensessioninview 是在 web 层写了一个filter 来打开和关闭 session,这样就表示在一次 request 过程中session 一直开着,保证了延迟加载在 session 中的这个前提。8.spring 的事务有几种方式?谈谈 spring 事务的隔离级别和传播行为。 声明事务和编程事务 隔离级别: - DEFAULT 使用数据库默认的隔离级别 - READ_UNCOMMITTED 会出现脏
37、读,不可重复读和幻影读问题 - READ_COMMITTED 会出现重复读和幻影读 - REPEATABLE_READ 会出现幻影读 - SERIALIZABLE 最安全,但是代价最大,性能影响极其严重 和传播行: - REQUIRED 存在事务就融入该事务,不存在就创建事务 - SUPPORTS 存在事务就融入事务,不存在则不创建事务 - MANDATORY 存在事务则融入该事务,不存在,抛异常 - REQUIRES_NEW 总是创建新事务 - NOT_SUPPORTED 存在事务则挂起,一直执行非事务操作 - NEVER 总是执行非事务,如果当前存在事务则抛异常 - NESTED 嵌入式事
38、务9.Hibernate 中的 update()和 saveOrUpdate()的区别. 摘自 hibernate 说明文档: saveOrUpdate()做下面的事: 如果对象已经在本 session 中持久化了,不做任何事 如果另一个与本 session 关联的对象拥有相同的持久化标识(identifier),抛出一个异常 如果对象没有持久化标识(identifier)属性,对其调用 save() 如果对象的持久标识(identifier)表明其是一个新实例化的对象,对其调用 save() 如果对象是附带版本信息的(通过 或 ) 并且版本属性的值表明其是一个新实例化的对象,save()它。
39、 否则update() 这个对象10.Spring 对多种 ORM 框架提供了很好的支持,简单描述在 Spring中使用 Hibernate 的方法,并结合事务管理。 getHiberanteTemplate 里面提供了 save,update,delete,find等方法。 简单说一个:如果配置了声明式事务,当执行getHibernateTemplate 的各种方法的时候,事务会自动被加载 如果没有配置事务,那么以上操作不会真正的被同步到数据库,除非配置了 hibernate 的autocommit=true8.spring 的事务有几种方式?谈谈 spring 事务的隔离级别和传播行为。
40、spring 事务分两种形式,声明式事务和编程式事务,spring 提供了一个事务的接口PaltformTractionManager 接口,针对不同的事务,spring 进行了不同的实现,对 hibernate 事务的实现 HIbernateTractionManager,对 JDBC 的JdbcTractionManager,DataSourceTractionManager 以及 JdoTractionManager。接口platformTractionManager 提供了三个方法,获取事务,提交和回滚的方法。*分享面试题二】Spring,hibernate,struts 的面试笔试题
41、(含答案)(声明:这里不是为其他商业利益,是为学习讨论使用)【郑重声明】:单纯接分将被删帖,希望大家有自己的感触 Hibernate 工作原理及为什么要用? 原理: 1.读取并解析配置文件 2.读取并解析映射信息,创建 SessionFactory 3.打开 Sesssion 4.创建事务 Transation 5.持久化操作 6.提交事务 7.关闭 Session 8.关闭 SesstionFactory为什么要用: 1. 对 JDBC 访问数据库的代码做了封装,大大简化了数据访问层繁琐的重复性代码。2. Hibernate 是一个基于 JDBC 的主流持久化框架,是一个优秀的 ORM 实现
42、。他很大程度的简化 DAO 层的编码工作3. hibernate 使用 Java 反射机制,而不是字节码增强程序来实现透明性。4. hibernate 的性能非常好,因为它是个轻量级框架。映射的灵活性很出色。它支持各种关系数据库,从一对一到多对多的各种复杂关系。2 Hibernate 是如何延迟加载? 1. Hibernate2 延迟加载实现:a)实体对象 b)集合(Collection)2. Hibernate3 提供了属性的延迟加载功能当 Hibernate 在查询数据的时候,数据并没有存在与内存中,当程序真正对数据的操作时,对象才存在与内存中,就实现了延迟加载,他节省了服务器的内存开销,
43、从而提高了服务器的性能。3Hibernate 中怎样实现类之间的关系?(如:一对多、多对多的关系)类与类之间的关系主要体现在表与表之间的关系进行操作,它们都市对对象进行操作,我们程序中把所有的表与类都映射在一起,它们通过配置文件中的 many-to-one、one-to-many、many-to-many、4 说下 Hibernate 的缓存机制1. 内部缓存存在 Hibernate 中又叫一级缓存,属于应用事物级缓存2. 二级缓存: a) 应用及缓存 b) 分布式缓存 条件:数据不会被第三方修改、数据大小在可接受范围、数据更新频率低、同一数据被系统频繁使用、非关键数据 c) 第三方缓存的实现
44、5 Hibernate 的查询方式 Sql、Criteria,object comptosition Hql: 1、 属性查询 2、 参数查询、命名参数查询 3、 关联查询 4、 分页查询 5、 统计函数6 如何优化 Hibernate? 1.使用双向一对多关联,不使用单向一对多 2.灵活使用单向一对多关联 3.不用一对一,用多对一取代 4.配置对象缓存,不使用集合缓存 5.一对多集合使用 Bag,多对多集合使用 Set 6. 继承类使用显式多态 7. 表字段要少,表关联不要怕多,有二级缓存撑腰=1.Hibernate 有哪几种查询数据的方式 (1)导航对象图查询 (2)OID 查询 (3)H
45、QL (4)QBC (5)本地 SQL 2.load()和 get()的区别 load 加载方法: Java 代码 Users user = (Users)session.load(Users.class, userId); Users user = (Users)session.load(Users.class, userId); get 加载方法: Java 代码 Users user = (Users)session.get(Users.class, userId); Users user = (Users)session.get(Users.class, userId); 两加载方法区
46、别: 区别 1:如果数据库中,没有 userId 的对象。如果通过 get 方法加载,则返回的是一个 null;如果通过 load 加载,则返回一个代理对象,如果后面代码如果调用 user 对象的某个属性(比如user.getPassword())会抛出异常:org.hibernate.ObjectNotFoundException; 区别 2:load 支持延迟加载,get 不支持延迟加载。 也就是说: Java 代码 Users user = (Users)session.load(Users.class, userId); Users user = (Users)session.load
47、(Users.class, userId); 这句代码不会去执行数据库查询,只有用到 user 时才会去执行数据库查询。 而: Java 代码 Users user = (Users)session.get(Users.class, userId); Users user = (Users)session.get(Users.class, userId); 则立即去执行数据库查询。 所以 Users user = (Users)session.load(Users.class, userId);不会执行任何 sql。 注意: Java 代码 Users user = (Users)sessio
48、n.load(Users.class, userId); System.out.println(user.getId(); Users user = (Users)session.load(Users.class, userId); System.out.println(user.getId(); 上面这 2 句代码,不会去执行数据库操作。因为 load 后会在hibernate 的一级缓存里存放一个 map 对象,该 map 的 key 就是userId 的值,但是当你 getId()时,它会去一级缓存里拿 map 的key 值,而不去执行数据库查询。所以不会报任何错。不会执行任何数据库操作。 3. Hibernate 工作原理及为什么要用? 原理: 1. 读取并解析配置文件 2. 读取并解析映射信息,创建 SessionFactory 3. 打开 Sesssion 4. 创建事务 Transation 5. 持久化操作 6. 提交事务 7. 关闭 Session 8. 关闭 SesstionFactory