Hibernate学习整理(Hibernate优化及HQL)

来源:互联网 发布:js实现图片转base64 编辑:程序博客网 时间:2024/05/21 12:40

6,Hibernate的优化(缓存、懒加载、抓取策略)(重点)

怎样检测Hibernate的性能:发出的sql语句越少

(1)    懒加载(需要将业务场景描述出来)

懒加载的类型:类的懒加载、集合懒加载、单端关联的懒加载(多对一),其中可以利用session.load()方法产生代理对象,在session.load()方法执行的时候并不发出sql语句,在得到其一般属性的时候发出sql语句,只针对一般属性有效而对标示属性无效。默认情况是懒加载。

在遍历的时候才发出sql语句——集合的懒加载,需要在配置中lazy=”true”懒加载,lazy=”false”不用懒加载,lazy=”extra”更进一步的懒加载(count,min,max,sum)。

懒加载主要解决的问题:解决hibernate在什么时候发出sql语句的问题。

(2)    抓取策略

解决的问题:发出什么样的sql语句

join        左外连接

如果把需求分析翻译成sql语句存在子查询,这个时候用该策略不起作用。

select    默认 先查询一的一端,再查询多的一端

subselect     子查询(可以解决n+1问题)

如果需要翻译成sql语句存在子查询,这个时候用该策略效率最高

总结:懒加载和抓取策略结合,研究对象时Set集合:

fetch     lazy        sql     什么时候发出sql语句               说明

join     false 存在子查询    当查询classes时把classes   这时候join没用

student全部查询出来            

   join         true         存在子查询    当遍历student时发出student   join没用

   join         true  不是子查询 session.get(classes)时全部查询出来  lazy没用

   subselect true/false  存在子查询              发出两条sql语句    如果lazytrue

                                                    在遍历集合;

                                                    如果lazyfalse

                                                                                                         一开始就发出

    select       true/false                                 发出n+1条语句              同上

注意:抓取策略只是提供给Hibernate的一种优化方式,只要是抓取策略能做到的都能用hql语句来做。     

(3)    缓存策略

缓存的生命周期

          生命周期就是session的生命周期

数据库的数据是怎样放入缓存的

          一级缓存存放的数据都是私有数据,把session存放在threadlocal

中,不同的线程是不能访问的,所以保证了数据的安全性。

session.refresh()方法可以将数据库的数据同步到缓存中

缓存中的数据是怎样放到数据库的

          session.flush()

          session的缓存内部,会去检查所有的持久化对象。

          如果一个持久化对象没有id值,则会发出insert语句,如果一个持久化对象有id值,则会去检查快照进行对比,如果一样,则什么都不做,如果不一样,则发出update语句。检查所有的持久化对象是否有关联对象,检查关联对象的级联操作,检查关联对象的关系操作。但是操作了这些之后,并没有清空缓存。

注意:在这里可以引发Hibernate的批量操作,如批量插入

可以每几十个数据刷新一下缓存,以避免内存溢出。

 

客户端怎样从缓存中把数据取出来的

客户端怎样把一个数据放入到缓存中

          利用session.save()session.update()session.load()session.get方法都可以将数据存放在一级缓存中

怎样把一个对象从缓存中取出

          利用session.get/load方法可以把数据从一级缓存中取出。

把缓存中所有的数据清空

          session.evict()可以将一个对象从一级缓存中清空

                            session.cleat()可以将缓存中的所有数据都清空

补充:页面缓存(ehcache,ohcache)场合:

       二级缓存:存放公有数据

       适用场合:数据不能频繁更新;数据能公开,私密性不是很强。

       Hibernate本身没有提供二级缓存的解决方案

       二级缓存的实现是依赖于第三方供应商完成的

              ehcache,oscache,jbosscache,swamcache

       二级缓存的操作:

       二级缓存存在sessionFactory中。

       生命周期,与sessionFactory保持一致

       使用Hibernate二级缓存,在Hibernate的配置文件中:

              开启二级缓存:

       true

              二级缓存的提供商:

       

              org.hibernate.cache.EhcacheProvider

 

导入ehcachejar

给某个类开启二级缓存:(让某个类或对象进入到二级缓存中)

方案一:在配置文件中

类全名”/>

方案二:在映射文件中

在类中: usage是缓存策略。

       使用二级缓存:

         session.get()session.load()把数据存在一级缓存和二级缓存中,查找时先从一级缓存中查找,再从二级缓存中查找。

        查询缓存:

在配置文件中:

true

只能在session.createQuery(“from  Classes”).setCacheable(true);表明classes里的所有数据要往查询缓存里放了。

(4)    hql语句

(5)    session:

session的产生

session的缓存——一级缓存

7,hql语句

8,细小知识点:

对象的序列化作用:让对象在网络上传输(以二进制的形式传输),Serializable是标识接口,即实现了此接口的类,将告诉虚拟机应将此类对应的对象变成二进制流,即将二进制的工作交给jvm做。

 

Hibernate配置文件中方言的作用:告诉Hibernate使用的是哪种类型的数据库。

 

Hibernate配置文件中,update

作用:根据持久化类和映射文件生成表

值:

validate 只验证持久化类和表对应是否正确

create-drop:当Hibernate启动时生成表,当Hibernate容器结束时删除表

create:每次启动Hibernate容器生成表

update:在启动Hibernate时会检查持久化类和表是否对应,如果不对应,则去创建,对应的时候则验证。

 

由表生成持久化类步骤:

将模式切换到MyEclipse Database Explore找到对应的表person

——>

点击hibernate reverse engineering进行 Hibernate反向工程

(前提是需要将当前项目转换成Hibernate项目:点击项目——>进入MyEclipse/Project Capabilities/Add Hibernate Capabilities

——>

接下来进入反向生成mapping映射文件和pojo类的配置。

 

主键的生成器总结

i increment说明:

Hibernate: select max(pid) from person

Hibernate: insert into person (pname, psex, pid) values (?, ?, ?)

主键的类型必须是数字

主键的生成是由Hibernate内部完成的,程序员不需要干预。

这种生成机制效率比较低,但是生成的主键是连续的

ii identity说明:

identity是按照主键的自增机制,MySQL有主键自增机制。

若出现field ‘pid’ doesn’t have a default value的错误就说明该表不支持自动增长机制。

新的主键的产生是由数据库完成的,并不是由Hibernate或者程序员完成的。

该表必须支持自动增长机制

效率比较高

iii assigned说明:

主键生成机制是assigned时,必须在程序中手动地设置其id值。

iv uuid说明:

UUID是由Hibernate内部生成的

主键的类型必须是字符串

注意:Hibernate内部是根据主键生成器来生成主键的,在客户端设置主键不一定起作用,在assigned的时候起作用。

对象的状态:

临时状态的对象:

持久化对象:只有处于持久化状态的对象session才管理

脱管状态的对象:

临时状态的对象——>持久化对象:

session.save();

session.update();

session.get();//当执行这个方法时,得到一个对象,是不需要再执行update语句的,因为此对象已经是持久化对象的状态了。

session.clear();//session中的所有对象都清空

session.evict();//把一个对象从session中清空,该对象成为脱管状态

注意:

当一个对象是持久化对象的时候,进行提交时,hibernate内部会让该对象和快照进行对比,如果一样,则不发生update语句,如果不一样,则发出update语句。一个对象是否是持久化对象是针对某一个session而言的。

注意:

当执行transaction.commit()的时候,hibernate内部会检查session

如果一个对象为临时状态的对象,则session不会管

如果一个对象是持久化的对象,如果有id值,并且和数据库对应,那么先把该对象与快照进行对比,如果一致,则什么都不做,如果不一致,则发出update语句。

如果一个对象时持久化状态的对象,没有id值,则会发出save语句。

 

注意:

一个session对应一个事务。

使用增强for循环时只能删除一次,若连续删除将会找不到位置,原因是增强for循环使用的是游标的方式。解决方案:用普通的for循环,或者新建一个Set集合,把原来set集合要保留的数据存放到新的Set集合中。

使用普通的for循环时,需要将set集合转换成为list集合:

List  sList = new ArrayList(set集合);

当在Set集合配置inverse=”true”不维护关系时,删除班级不会级联更新关系,所以会抛出主外键约束的错误。

总结:

1,Hibernate的组成部分:

持久化类

         实现对应的序列化接口

         必须有默认的构造函数

         持久化类的属性不能使用关键字

         标示符

映射文件

         类和表的映射、属性和字段的映射、关系的映射

         主键生成器 incrementidentityassigneduuid

         cascade是操作两个对象的关系

         inverse 是对象与外键之间的关系           

配置文件

         描述了数据库的连接信息

         存放了映射文件的信息

         其他信息

2,Hibernate的流程

Configuration              接口,加载配置文件

SessionFactory(线程安全,单例,信息共享)      接口,存储配置文件的信息、映射文件的信息、持久化类的信息

Session    与数据库的会话、crud的操作都是由session完成的、事务是由session开启的,两个不同的session只能用各自的事务、决定了对象的状态、创建完session相当于打开了数据库的链接

Transaction:事务默认不是自动提交的,必须由session开启,必须和当前的session绑定(两个session不可能公用一个事务)

 

3,session.getCurrentSession的用法:

4, 

(1)    hibernate的配置文件中:

thread

(2)    不需要写session.close()方法,在事务提交的时候会自动关闭(由hibernate内部完成)。

(3)    crud都需要事务

因为是一个线程,所以整个方法中一个session,一个事务

保证了整个业务操作的安全性。

 

5,hibernate的查询方式

(1)    hql(hibernate query language) query

”from Classes””select cid,cname from Classes”其中带select和不带select的查询结果是完全不相同的,不带select查出来的listClasses对象数组,而带selectlist结果里存放的是objct数组,并且每一个object对象里存放的又是关于属性的数组。

如果需要用带select的语句并且要求查询出来的是Classes对象,则需要利用发射的机制,

Session.createQuery(“select new Classes(带属性的构造函数)(全类名) from Classes where cid=:cid”)返回一个Query对象

query.setLong(“cid”,1L);

query.uniqueResult();//返回唯一的结果对象

无论单表、多表,order by,group by,sum,min,max,avg,having等都适用。

关于一对多的操作:

内连接:

session.createQuery(“from Classes   inner  join  fetch  c.students”).list();采用这种迫切内连接将会将结果转换为Class的结果集合。

外连接:

Session.createQuery(“from Classes   left outer join fetch c.students”).list();转换成Class对象的结果集

其中转换成哪个对象的结果集是看from后面跟着的是哪个类

只取其中部分字段,采用创建javaBean来实现:

Session.createQuery(“select new cn.itcast.hibernate.ClassView(c.cname,s.sname) from Student s left outer join s.classes c”).list();注意这里不能使用fetch

在多对多三张表联合查询时很可能会出现重复数据的现象,这时候可以将查询出来的list集合转换成set集合,然后再转变为list回来。

(2)    Criteria query

(3)    Native query

HQL总结:

1,如果页面上要显示的数据和数据库中的数据相差甚远,利用带select的构造器进行查询是比较好的方案。

2,如果页面上要显示的数据和数据库中的数据相差不是甚远,采用迫切连接。

3,如果采用迫切连接,from 后面跟着的对象就是结构主体。

0 0
原创粉丝点击