Hibernate面试题&答案

xiaoxiao2021-02-28  15

讲讲一下orm框架 以及各个orm框架的区别 答:o---Object对象。 r---关系数据库。 m---映射文件。 orm可以说是一项为了实现面向对象与关系数据库的不匹配而产生的一种框架,简单的说:orm是通过使用描述对象与关系数据库之间映射的元数据, 将Java程序中的对象通过自动持久化同步到关系数据库,本质上来说就是把数据从一种形式转换成另一种形式。 orm类型 映射关系 开发效率 数据库移植 hibernate: 全自动 实体类和数据库 自动生成sql 不同数据库类型的支持 ibatis: 半自动 实体类和SQL语句 需要编写具体的sql 标准SQL方便移植 hibernate 的原理及其步骤 1.读取配置(Configuration)*.cfg.xml。 2.使用Configuration创建SessionFactory(线程安全)。 3.使用SessionFactory创建Session(线程不安全,使用本地线程TheradLocal解决)。 SessionFactory提供了两种方式得到session。 1 openSession:得到的session是线程不安全的,可以通过本地线程 Threadlocal机制解决,把session放入Threadlocal中,达到隔离线程的目的,得到的session需要手动关闭。 2 getCurrentSession可以解决要在事务范围内 session 线程不安全问题,因为它总是把session绑定到当前线程,并且在事务提交的时候自动关闭session。但需要配置:<property name="hibernate.current_session_context_class">thread</property><!--针对jdbc的--> 自动关闭session 4.利用Session启动事务(Transaction)。 5.利用Session进行业务操作。 6.提交事务(调用commit()方法)。 7.关闭Session(调用close()方法)。 说出Hibernate的核心类和接口: Configuration:管理从配置文件(*.cfg.xml)中读取的信息。 SessionFactory:根据配置信息创建一个SessionFactory实例。 Session:持久化方法是通过Session来完成的。 Transaction: 事务管理。 Query:查询接口。 SQLQuerry:sql查询的查询接口。 hibernate 实体的3种状态 1.瞬时状态:这种状态一般都是刚new出来,这种状态下的数据还没有与session有关联不能与数据库同步。 2.持久化状态:当数据与session产生关联后就由瞬时状态转变为持久化状态,只有与session产生关联后数据才能同步到数据库。 3.离线状态:这种状态曾经被持久化过,而且数据库中也与之有关联,但是当前session已经关闭,与Session已经没有任何的关联, 数据库中同步的数据是在Session关闭之前最后一次提供的数据,当session关闭之后数据就不能同步到数据库了。 几种状态之间是可以互相转换的:瞬时状态可以通过session进入持久化状态,持久化状态通过关闭Session进入离线状态, 而离线状态可以通过update或saveUpdate等方法回到持久化状态,可以通过Delete回到瞬时状态。 hibernate的几种查询方式 hibernate的sql查询接口是什么 1.hql查询:hql是面向对象而不是面向数据库的查询,Query作为hql的查询接口,Query通过Session创建查询语句(查询语句的原来是表名, 现在是属性类名,原来是字段,现在是属性)通过session调用createQuery方法实现语句查询。 hql支持两种查询方式:占位符(问号)与命名参数(冒号),不支持*操作,不适合动态查询。 2.sql查询:SQLQuery就是sql的查询接口,此时查询就是sql语句表名就是表名字段名就是字段名,默认查询出来的list不是属性类对象, 而是Object数组,可以通过SQLQuerry.addEntity(属性类.class)进行转换。 也支持命名参数与占位符,但是它的移植性差。 3.qbc查询:Criteria是qbc的查询接口,这种查询方式不需要sql语句也不需要hql查询方法,不过对于太复杂的查询还是不建议使用, 通过Criteria使用Session创建出来的实例.add(Restrictions.eq("字段",条件))来进行条件查询。 4.qbe查询:通过使用样板来查询数据库中的记录,给出要查询记录的所有字段条件,如果不给出查询条件那么此时从属性类中拿出来的属性 都是等于null或0,因此查不出任何记录。 什么是hibernate主键生成机制 举例说明 主键生成机制就是通过在*.hbm.xml文件中generator标签里进行配置,通过使用不同的主键机制而产生不同的主键性能。 如:assigned,主键的生成值完全由用户决定,与底层数据库无关。用户需要维护主键值,在调用session.save()之前要指定主键值。 hilo 会多生成一个表,使用高低位算法生成主键。 increment(英扑来慢特),由hibernate管理主键,自动以递增的方式生成字段值,每次增量为1,该主键必须为Integer类型。 identity(安踢踢),由数据库生成标识符,identity是由数据库自己生成的,但这个主键必须设置为自动增长,前提条件是数据库支持自动增长字段类型, 有可能增长的幅度不一定为1。 uuid,数据类为String类型,由 Hibernate 通过128位uuid算法生成16进制数值(编码后以长度32的字符串表示)作为主键。 sequence(赛宽丝) 采用数据库提供的 sequence(序列) 机制生成主键。如 Oralce 中的Sequence。 foreign 使用另外一个相关联的对象的标识符作为主键。 native 由Hibernate根据使用的数据库自行判断采用 identity、hilo、sequence 其中一种作为主键生成方式。 阐述一下hibernate的映射 在关联映射中一对多 和 多对多 是如何实现的 要注意什么问题? 映射分为四种: 1 基本类型的映射。 2 集合映射:加一个表,主键关联起来,1 list映射 有序可重复,2 set 无序不可重复,3 bag 无序可重复,4 map映射。 3 级联映射:1 一对一,2 一对多,3 多对多 分为单向映射(一方持有另一方的实体或集合),双向映射(彼此持有对方的实体或集合)。 - 一对一:1 外键关联,把外键对应的字段加上唯一约束。 2 主键关联,双方共用一个主键,采用的主键生产机制是foreign。 - 一对多:使用的是级联与反转。 - 一般使用的是双向关联,在一方放多方的集合,在多方放一方的实体。 - 反转:1. 如果不用反转 hibernate默认由一方维护关联关系的字段,做法是一个一个的对集合里面的数据进行插入, 关联字段为空,之后发一条一条的uodate语句去更新关联字段。 - 如果用反转 表明将关联关系维护权交给另一方(多方)管理,由多方维护关联字段的话,不会产生update语句, 带来了性能上的提升。 - 使用反转:在one-to-many或many-to-many的集合定义中使用,inverse=true”表示该对象不维护关联关系, 该属性的值一般在使用有序集合时设置成false(注意hibernate的缺省值是false), one-to-many维护关联关系就是更新外键,many-to-many维护关联关系就是在中间表增减记录。 - 级联:当主对象做操作时候其关联的对象也做与主对象类似的操作,可以减少代码,一般在一方使用, 因为如果在多方使用的话那就没什么意义了。 注意:级联时给关联对象设置id时需要注意,hibernate会对关联的对象进行修改,如果关联对象在数据库不存在的时候会报错。 使用级联删除时需要关联对象持久化,否则报外键约束错误。 - 多对多:加一个中间表,many-to-many,实则是转成两个一对多,而中间表是放了双方的id作为联合主键,和约束。 使用双向多对多的时候,使他们同时指向一个表,不能会创建两个中间表出来,但只有一个中间表会保存到数据, 并且要指明关联字段维护权的问题,一个使用inverse="false" 一个使用inverse="true",否则会出现主键重复的问题。 4 继承映射:1 每个类一张表,2 每个子类一张表,父类没有表,3 所有类一张表 5 组件映射:它只是一个普通的java类,没有映射文件,但是它不是hibernate的实体,而是实体的一部分,将可重用的部分提取出来, 使它可以进行重用。 hibernate的缓存是什么 用来干什么的 什么时候用什么方法刷新缓存 各种缓存里放的是什么东西 使用缓存应该注意什么 - 缓存是什么:缓存是介于物理数据源与应用程序之间,是数据库数据在内存中的存放临时copy的容器, 其作用是为了减少应用程序对物理数据源访问的次数,从而提高了应用的运行性能。 - 使用缓存的条件。 1.读取大于修改。 2.数据量不能超过内存容量。 3.可以容忍出现无效数据。 - 一级缓存,是session共享级别的,hibernate内置的缓存,里面存放的实体,因为它是hibernate内置的缓存不能控制缓存的数量, 所以要注意大批量操作数据时可能造成内存溢出,可以用clear方法清除缓存中的内容。 - 二级缓存,SessionFactory级共享,是放在配置文件中,实现为可插拔,里面存放实体。 1 如果使用二级缓存就需要在配置文件中配置开发二级缓存,使用evict(属性类.class)方法清除二级缓存。 2 开启二级缓存的步骤:二级缓存的配置和使用。 - 开启二级缓存,修改hibernate.cfg.xml文件 在hibernate的配置文件中使用property属性开启。 <property name="hibernate.cache.use_second_level_cache">true</property> - 指定缓存产品提供商,修改hibernate.cfg.xml文件 指定缓存产品的提供商(EhCache(衣艾去k其)),也是在配置文件中用property属性指定。 <property ame="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</property> - 指定那些实体类使用二级缓存(两种方法) - 在映射文件中采用<cache>标签 <cache usage="read-only"/> usage="read-only"是“只读”缓存策略,这个<cache>标签只能放在<class>标签的内部,而且必须处在<id>标签的前面。 - 在hibernate.cfg.xml配置文件中,采用<class-cache>标签。 <class-cache class="com.lxit.hibernate.Classes" usage="read-only"/> 注意:这个<class-cache>标签必须放在<mapping>标签的后面。 - 查询缓存,Query,Criteria(查询缓存)由于命中率较低,所以hibernate默认是关闭的。 1 在配置文件中使用property属性打开查询缓存开关。<property name="hibernate.cache.use_query_cache">true</property> 2 在程序中手动启用查询缓存query.setCacheable(true)或criteria.setCacheable(true),是先读取查询缓存,再把读出来的数据放入查询缓存中。 SessionFactory中提供了evictQueries()方法用来清除缓存中的内容。 3 如果查询的是实体放入的是id,否则就放入整个结果集。 4 查询缓存里面放的是: 1 查询的list里面放的是实体,会把实体放入的一级缓存与二级缓存里面,则查询缓存里面放的是id, 会根据id到一级缓存与二级缓存里面去找相对于的数据,找不到会发sql到数据库中找。 2 如果查询的list里面放的不是实体,只是查某些字段,查询缓存里面放的是查询的结果集。 - 使用缓存应该注意什么: 1 使用缓存时应该用于的系统是查询大于修改,因为查询出来的数据会放入缓存中下次直接从缓存中拿出来,不用数据库发sql进行查询, 这样大大提升了系统的性能,而修改过多每次查询都是不同的数据,每次都要重新到数据库中拿值,这样就降低了项目的性能。 2 数据量不能超过内存容量,否则会报系统内存溢出错误。 - 使用一级缓存的问题,当Session关闭后里面的数据就没有了,因为不能控制,所以要注意大批量操作数据时可能造成内存溢出。 - 使用二级缓存的问题,要注意它的命中率,如果命中率太低对系统性能的消耗会很大。 - 查看二级缓存的命中率: (1) 在hibernate的配置文件中要打开命中率开关,<property name="hibernate.generate_statistics">true</property>。 (2) 通过sessionFactory.getStatistics().getSecondLevelCacheHitCount();,查看命中的次数(是从二级缓存中查询出来的)。 通过sessionFactory.getStatistics().getSecondLevelCacheMissCount());,查看没有命中的次数。 load与get save与persist saveorupdate与merge list与iterator 区别 它们的是把数据放入缓存中的。 1 load(漏斗)(支持懒加载)根据id在查询时不会立即访问数据库,而是在需要使用时才会访问数据库,如果id不存在会报找不到id错误。 get(不支持懒加载)根据id查询时会立即访问数据库,如果id不存在则返回null。 2 save(赛屋)保存数据登记相应的动作到对列中,并把实体放入session中,等待flush方法调用同步数据库。 persist(炮赛丝特)在事务外不会产生增加语句 ,在主键生成机制是native中可以看到。 3 merge(冒杰) 调用merge对象就不会变成持久化状态的,当id在缓存中存在对应的实体时,就是把两个合并。 saveOrUpdate碰到这种情况会报错,因为相同的主键在session中已经存在另一个object。 4 list它是一次性把所有的数据查询出来,而且会把查询出来的数据放入一级缓存中,也会放入二级缓存,会把读出来的数据放入查询缓存中, 但是不使用一级缓存,同样也不使用二级缓存,list会使用查询缓存。 iterator不会把查询出来的数据放入一级缓存中,也不会放入二级缓存,但是使用一级缓存,同样会使用二级缓存,不使用查询缓存, 因为迭代器会先到数据库中把id都取出来,然后真正要遍历某个对象的时候先到缓存中找,如果找不到,以id为条件再发一条sql到数据库, 这样如果缓存中没有数据,则查询数据库的次数为n+1。 项目中用list与iterator:先使用list查询,因为它会把查询出来的数据放入缓存中,然后使用iterator,它会去缓存中查找数据。 什么是懒加载(延迟加载) 懒加载用什么技术实现 如何解决session关闭导致的懒加载问题 解决的方案有缺点吗 懒加载:1. 当具体确定用到某个数据时才会去加载数据库,跟我们以前讲的JVM的类装载器差不多,用谁加载谁。 - 懒加载使用的是代理技术来完成的,代理类就是加载对象的子类(系统定义的),如果把加载对象设置成final修饰那么就不能使用懒加载。 - 当Session关闭时会造成懒加载的问题,可以使用OpenSessionInView模式来完成懒加载问题,通过过滤器来实现, 在最开始访问过滤器时就把Session打开,直到执行完所有命令返回结果后关闭Session,这样就不会出现懒加载问题。 - 同样这种方式也带来了问题,事务扩大了,导致资源等待时间过长,session范围变大,如果加载页面的时间过长, 如网速比较慢,内存时间过长,导致系统性能下降,数据库连接不能及时释放。 概念:1 lazy的概念,指在需要数据的时候才发出sql。 2 lazy策略只是在session打开期间才是有效的。 3 Hibernate加载本身就是延迟加载,在*.hbm.xml配置文件中<class>里配置lazy="false"将其改为非延迟加载。 4 Hibernate属性的延迟加载,在*.hnm.xml配置文件中<property>里配置lazy="false"即可。 5 类的延迟加载并不影响属性的延迟加载。 6 连接抓取会使lazy失效。 讲讲一下hibernate的抓取策略 hibernate的抓取分为:抓取策略就是抓与当前对象有关联的实体或集合。 连接抓取 fetch="join":通过select语句使用外连接来加载其关联实体或集合。? 查询抓取 fetch="select":在查询当前班级表后会另外发送一条select语句抓取当前对象关联实体或集合。 子查询抓取 fetch="subselect":另外发送一条select语句抓取在前面查询到的所有实体对象的关联实体或集合,通过子查询in完成 批量抓取(batch-size="数量"):给的数量是多少就一次抓取多少条记录(前提是数据库中有那么多记录)。 hibernate如何处理大数据量? 1.使用循环方法进行小量同步来清除缓存,当循环方法加载完指定的数量后就调用flush把数据同步到数据库,然后调用clear清除缓存。 2.用(无状态Session)StatelessSession接口:它不和一级缓存、二级缓存交互,也不触发任何事件、监听器、拦截器, 通过该接口的操作会立刻发送给数据库,与JDBC的功能一样。 3.使用Query调用executeUpdate()执行批量更新,会清除相关联的类二级缓存,也可能会造成级联,和乐观锁出现问题。 4.使用分页机制,setFirstResult(2)表示从第3条记录开始。setMaxResults(10)取10条记录。 什么是乐观锁与悲观锁? 乐观锁:在数据库中加一个version(版本号),字段属性为int,在读取数据时把版本号一同读出,在更新数据后数据库自动为版本号加1, 如果在更新过程中出现什么情况而没有及时提交,而此时另一个人对此数据进行了更新,更新完后版本号自动加1, 此时数据库中的版本号已经比之前读出的版本号大1,如果提交的版本号小于或等于数据库中的版本号那么就会报当前数据已过期。 - 为什么等于也过期呢? - 因为提交时版本号会自动加1后再去与数据库中的版本号做比较。 悲观锁:锁住之后在没有提交之前任何人都改变不了原数据,但是有一个问题:在提交之后, 之前没提交时别人修改过但是没有修改成功的数据就会修改成功,使用LockMode.UPGRADE完成。 你是如何进行Hibernate的性能优化的 在使用查询数据时第一次使用list方法查询,以后使用迭代方式查询,因为list查询它只会把数据放入缓存中而不会使用缓存, 迭代器查询出的数据它不会放入缓存但是会使用缓存,有一点注意,迭代器不使用查询缓存,list会使用查询缓存。 处理大数据量时使用优化方法(请看第12题的优化方式)。 使用懒加载,关联数据,主键生成机制也是对系统的一种优化。 根据命中率使用缓存,命中率过底部建议使用缓存。 在页面显示时如果有视频就尽量使用懒加载。 关联时使用双向双向映射。 讲讲hibernate的监听器 它有什么作用 细说一下hibernate保存数据的步骤? hibernate的数据保存是通过缓存来实现的,通过Configuration加载配置文件来创建SessionFactory,SessionFactory是线程安全的, 使用SessionFactory创建Session,创建Session有两种方式,使用openSession得到的Session是线程不安全的,可以通过本地线程解决这个问题, 需要手动关闭Session,还可以使用getCurrentSession得到的Session是线程安全的,它是自动关闭Session,通过Session调用save或saveOrUpdate方法, 调用方法时会触发一个事件,事件会通知监听器,触发监听器里的方法,然后把对象放进缓存登入动作,等待flush(福拉西)刷新, 提交事务,从缓存中获取数据同步到数据库,一般是指定字符串id。 调用两次flush是否会发两条sql,不会,因为它第一次会发送sql,但是它会登记的动作清除掉,flush是根据登记的动作发送sql的。 - 自定义监听器 1 实现监听器接口 如:SaveOrUpdateEventListener 重写onSaveOrUpdate方法。 2 注册监听器 两种形式: 1 在hibernate的xml里面根据方法配置。 2 通过编程式,可以多个监听器类型之间共享监听器的实例,配置的每次都会产生一个新实例。 hibernate保存数据:调用save方法把对象放进缓存登入动作,等待flush(福拉西)刷新,提交事务,从缓存中获取数据同步到数据库。 spring是如何整合hibernate的 1spring提供的LocalSessionFactoryBean,创建Sessionfactory, 注入数据源dataSource,hibernate属性hibernateProperties和映射文件。 2 给HibernateTemplate类注入sessionFactory的实例,之后就可以用HibernateTemplate类封装的hibernate的api操作。 3 继承 HibernateDaoSupport类使代码更加简洁,给HibernateTemplate类注入sessionFactory, 之后就可以用它的getHibernateTemplate方法获得模板类。 4 事务整合,采用hibernate的事务管理器。 你有什么hibernate的最佳实践吗什么是离线查询 组装sql时需要Session,查询时不需要Session这是离线查询。 离线查询利用DetachedCriteria类使你在一个session范围之外创建一个查询,并且可以使用任意的Session来执行它,用在动态sql的构建上。 简单说明:就是在Session的范围之外创建查询方式。 hibernate查询单条记录有几种方法 唯一记录使用Session调用uinqueResult方法,当你确定本次查询只有一条记录可以用uinqueResult返回一个实体对象。 get方法 load方法。 你做项目为什么使用hibernate 为什么不使用hibernate 文档齐全,全自动的操作,自动生成sql等功能。 使用hibernate有几方面的好处,它的缓存机制可以为系统查询时节省资源,主键机制,自动生成sql等性能比较强,使用比较灵活, 而且hibernate还可以在不同数据库类型的支持,跨数据库的功能,与底层数据库分离,可移植。 不使用hibernate是因为在一些系统里数据量大或是更新比较频繁,而这些原因就会因为hibernate的缓存机制导致系统内存消耗过大, 系统性能下降,还有一些保密性较高的如:财务数据,私人信息等系统也不适合hibernate,不能使用sql的很多功能 存储过程等。 jdbc与hibernate不能共存,因为会导致hibernate的缓存失效。 用过hibernate注解吗 说出几个 @Entity:标记为持久类映射 @Table:指定表名 @Id @GeneratedValue @GenericGenerator:主键生成机制 @OneToMany @ManyToOne @JoinColumn:关联字段 其它注解: @Resource:标注在对象上,可以代替以前的set方法。 @Controller:表示action层。 @Service:表示service层。 @Repository:表示dao层。 hibernate为什么能跨数据库? 因此在它的底层封装了很多数据库的方言,实现了跨数据库的功能,根据配置的方言,产生不同的sql,使用URL通过元数据得到需要使用什么数据库。 使用hibernate碰到什么问题? - 大数据量问题。 - hibernate最好不要与其它系统共存,如:JDBC - 使用一级缓存的问题,当Session关闭后里面的数据就没有了,因为不能控制,所以要注意大批量操作数据时可能造成内存溢出。 - 使用二级缓存的问题,要注意它的命中率,如果命中率太低对系统性能的消耗会很大。 - 使用缓存都会有存在无效数据的问题,使用缓存应该注意查询要大于修改,而且数据量不要过大。 性能优化 1.懒加载 2.List 和 iterator 3.批量处理 4.无状态session 5.分页
转载请注明原文地址: https://www.6miu.com/read-800118.html

最新回复(0)