企业框架-1 Hibernate框架

第三个阶段主要是企业框架的学习。目前主流的企业框架有SSH(Spring+Struts2+Hibernate)和SSM(Spring+SpringMVC+Mybatis)框架。首先对Hibernate框架进行总结,这部分也是企业框架中最难的。这部分内容主要包括:ORM关系映射、Hibernate关联映射、HQL查询、Criteria查询和注解与缓存,下面依次介绍。
一、Hibernate入门

1、Hibernate简介

框架:是一个提供了可重用的公共结构的半成品

作用:优秀的Java 持久化层解决方案、对象-关系映射(ORM)工具、简化了JDBC 繁琐的编码

2、持久化

定义:程序数据在瞬时状态和持久状态间转换的过程。无论是转换为持久态还是瞬时态,都称为持久化

保存在内存中的数据是瞬时的,而保存在数据库或硬盘的数据是持久的。

3、对象-关系映射 ORM(Object Relational Mapping)

作用:保存着对象与关系型数据库表的映射信息,协助数据转换。

编写程序的时候,以面向对象的方式处理数据。而保存数据的时候,却以关系型数据库的方式存储

4、使用Hibernate的步骤

1->部署jar包                            2-> 编写Hibernate配置文件hibernate.cfg.xml

3->创建持久化类和映射文件  4->使用Hibernate API增删改查

5、Hibernate中Java对象的三种状态

瞬时状态:实体对象在内存中存在,在数据库和session缓存不存在。

持久状态:持久化对象在数据库和session缓存中存在,与session实例关联,与数据库相关记录对应

游离状态:持久化对象脱离了session缓存,在数据库中存在而在session缓存中不存在

状态转换:

new                                                    ->瞬时态(临时态)

get() load()方法                                ->持久态

save() saveOrUpdate()方法            瞬时态 ->持久态

delete()方法                                      游离态|持久态->瞬时态(临时态)

evict() clear() close()方法                持久态->游离态

update() merge() saveOrUpdate()   游离态->持久态

get() load()方法区别:load()在使用对象才会加载,存在延迟加载问题。load返回值不能为null,否则抛空指针异常。而get()返回对象可为空,会即时加载。

update() merge()区别:merge操作的是实体的代理对象 不会改变对象原有的状态

6、脏检查

当一个持久化对象加入Session缓存时,Session会为该对象的属性复制一份快照。当清理Session缓存时,会先进行脏检查,即比较持久化对象的当前属性与它的快照,来判断实体对象的属性是否发生了变化。如果发生变化,则根据脏对象的最新属性来执行相关的SQL语句。

7、缓存清理机制

当Session缓存中对象的属性每次发生了变化,Session并不会立即清理缓存和执行相关的SQL update语句,而是在特定的时间点才清理缓存。当调用commit()方法时会先清理缓存,然后再向数据库提交事务。调用flush()方法,执行查询操作时持久化对象属性发生变化,都会先清理缓存。
二、Hibernate关联映射

1、类与类之间的关系

关联、依赖、泛化、实现、组合、聚合

最常用的是:关联关系

关联关系分:一对多(多对一); 多对多; 一对一;

2、关联关系在Hibenate的应用

通过配置的方式(注释或XML文件),将对象间的关联关系映射到数据库上,方便完成多表的持久化操作。

3、<set>节点的cascade属性

cascade属性指定了什么时候执行级联操作

值: none: 默认值,不级联操作  save-update:保存或更新时级联操作

delete:删除时级联操作  all:都级联操作

级联删除:先维护关系,再级联删除。先删主表,再删字表

<set cascade="delete"  inverse="true"></set>

级联修改:先维护关系,再级联修改。

级联增加:先级联增加,再维护关系。 先添加主表,再添加字表

4、<set>节点的inverse属性

inverse属性指定了关联关系中的方向,指定谁负责维护关系

值:false,默认值 ,由自己维护关联关系

true,不负责维护关联关系,由对方负责维护

一般"一"方的inverse设置为true,由"多"方维护关系

ag:设置inverse为true,级联删除表字段时,会产生相关表的update sql

5、<set>元素的order-by属性

order-by属性用于在数据库中对集合排序  order-by="ename asc"

6、Hibernate检索策略

1.立即检索:立即加载与当前对象关联的对象,但是需要执行多条select语句

2.延迟检索:在第一次访问关联对象时才加载其信息。

优点:由应用程序决定需要加载哪些对象,可以避免可执行多余的select语句,以及避免加载应用程序不需要访问的对象。因此能提高检索性能,并且能节省内存空间;

缺点:应用程序如果希望访问游离状态代理类实例,必须保证他在持久化状态时已经被初始化;

3 .迫切左外连接检索:通过左外连接加载关联对象,为立即检索策略,但select语句少。

优点:对应用程序完全透明,不管对象处于持久化状态,还是游离状态,应用程序都可以方便的从一个对象导航到与它关联的对象;使用了外连接,select语句数目少;

缺点:可能会加载应用程序不需要访问的对象,白白浪费许多内存空间;复杂的数据库表连接也会影响检索性能;。

延迟加载策略:Lazy="true/false"    表示是否使用延迟加载

抓取策略:fetch="select/join" 表示加载关联对象的查询语句形式以及加载关联对象的时机

检索策略:batch-size="3"      表示批量检索的条数

批量发送:<property name="hibernate.jdbc.batch_size">20</property>

7、Open Session In View模式

定义:在用户的每一次请求过程始终保持一个Session对象打开着。

运用:把session 事务放到过滤器中,统一集中处理。用Filter过滤器在请求到达之前打开session,在响应之前关闭session
三、HQL查询

1、Hibernate检索方式

QBC(Query by criteria)其API封装了基于字符串的查询语句

HQL(Hibernate Query Language)提供了一种面向对象的查询语言

OID(Object identifier)是对象标识符,用来建立内存中的对象与数据库表中记录的对应关系

本地SQL检索(使用本地数据库的SQL查询语句)

导航对象图检索(根据已经加载的对象,导航到其他对象)

2、HQL使用步骤

1.获取Session对象    Session session = HibernateSessionFactory.getSession();

2.编写HQL语句   String hql = "from User where username like '%a%'";

3.创建Query对象  query = session.createQuery(hql);

4.执行查询,得到查询结果    list()方法  iterate()方法

3、投影查询:查询一个持久化类的多个属性值

将每条查询结果封装成Object对象

将每条查询结果封装成Object数组

将每条查询结果通过构造函数封装成对象

4、参数绑定

按参数位置绑定   = ?  ?     第一位 0   第二位 1  …

按参数名字绑定  :name   (name, "aa")

5、排序、统计、分组

Session.createQuery("Select count(*) from User group by id having count(*)>20")

.uniqueResult();

6、命名查询:在映射文件中定义字符串形式的查询语句

<query name=" findStudentByName ">

<![CDATA[from Emp e where e.job = :job]]></query>

在类中:Query q = session.getNamedQuery("findStudentByName");

7、子查询与连接查询

子查询:where字句使用,且子查询必须用圆括号包围

" from Student where score > all(select score from Student where sname='a' or sname='b')"

连接查询:

内连接:join;              迫切内连接:join fetch;

左外连接:left join;迫切左外连接:left join fetch;

右外连接 :right join   全外连接: full join

迫切连接不仅指定了连接的查询方式,而且显式指定了关联级别的检索策略。

8、分页查询

session.createQuery("from User")

.setFirstResult((pageIndex-1)*pageSize).setMaxResults(pageSize).list();
三、QBC(Query By Criteria)

1、Criteria查询:又称对象查询,采用对象的方式封装查询条件。

使用步骤:

获取session对象     Session session = HibernateSessionFactory.getSession();

创建criteria对象      Criteria criteria = session.createCriteria(User.class);

这里的criteria实例实际上是 一条SQL语句:select * from user

执行查询,得到查询结果   result=criteria.list();

2、查询条件

hql通过query.set***()来添加条件  criteria通过criteria.add来添加条件

比较运算  Restrictions.eq( )

范围运算  Restrictions.in( )

字符串模式匹配  Restrictions.like( )

逻辑运算  Restrictions.or( )

集合运算  Restrictions.isEmpty( )

3、投影查询

使用org.hibernate.criterion.Projections类来支持Criteria投影

.setProjection(Property.forName("dname")).list();

4、连接查询

Criteria接口提供了createAlias()方法建立内连接

只支持:内连接和迫切左外连接

.createAlias("g.students", "s",CriteriaSpecification.LEFT_JOIN)

5、分页查询

.addOrder(Order.desc("salary")).setFirstResult(0).setMaxResults(2).list();

6、排序 分组 统计

.add(Projections.groupProperty("roleid")).add(Projections.count("id"))分组 统计

.addOrder(Order.asc("salary")).addOrder(Order.desc("empNo"))升序 降序

7、DetachedCriteria和Criteria功能对比

Criteria是由Session对象创建的,DetachedCriteria创建时不需要Session对象

可以把DetachedCriteria作为方法参数传递来构造查询条件

DetachedCriteria.forClass(User.class);.add(Restrictions.eq("roleid", 1)
四、原生SQL查询

使用底层数据库的SQL特性,来生成一些特殊的查询语句

步骤和HQL查询类似

session.createSQLQuery("select * from student")

.addEntity(Student.class).list();
五、注解与缓存

1、Hibernate注解

Hibernate提供了Hibernate Annotations扩展包。它可以替换复杂的hbm.xml文件,使得Hibernate程序开发大大简化

2、使用Hibernate注解的步骤

1.添加jar包

2.使用注解配置持久化类以及对象关联关系

3.在Hibernate配置文件(hibernate.cfg.xml)中声明持久化类

3、常用Hibernate注解

@Entity 将一个类声明为一个持久化类

@Id 声明了持久化类的标识属性

@GeneratedValue 定义标识属性值的生成策略

@Table 为持久化类映射指定表

@Column 将属性映射到列(字段)

@Transient  将忽略这些属性

@OneToOne   建立持久化类之间的一对一关联关系

@OneToMany  建立持久化类之间的一对多关联关系

@ManyToOne  建立持久化类之间的多对一关联关系

@ManyToMany 建立持久化类之间的多对多关联关系

4、使用注解配置命名查询

@NamedQuery(name = "selectEmp", query = "from Emp where name like :ename")

5、Hibernate缓存

1 一级缓存:session级别的缓存,依赖于session生命周期

不受我们管理,我们只能通过session.evict() 、session.clear() 清除一级缓存。save()、update()或 saveOrUpdate()、load()、 get()、list()、iterate() 我们做上述操作的同时,hibernate会把上述操作的对象放入到session缓存中

2 二级缓存:sessionFactory级别的缓存,依赖于sessionFactory的生命周期。 hibernate默认提供的是HashtableCache的二级缓存实现,它仅仅用于开发测试。

我们正常情况会去配置一个第三方的缓存插件(EHCache  OSCache

SwarmCache  JBOSSCache);二级缓存是默认是开启的。通过在配置

文件中添加cache.use_second_level_cache,值为false可以关闭

3 查询缓存:依赖于二级缓存

主要是用于通过hql或qbc查询的缓存,主要是对list起作用 ,是需要我们开启的;查询缓存默认是关闭的,通过在配置文件中配置cache.use_query_cache,值为true来开启;开启之后,还不能使用,必须在程序中设置query.setCacheable(true);

6、二级缓存配置步骤

1 添加ehcache.jar

2 在src下,添加ehcache.xml文件,文件模板在hibernate源代码文件的etc文件夹下

3 在配置文件添加cache.provider_class,值为:net.sf.ehcache.hibernate.EhCacheProvider

4 在要使用缓存的类中,在class节点下配置 <cache usage="read-write"/>

read-write:读写型,缓存在数据变化时触发更新,适于经常被读但很少修改的数据,可以防止脏读

read-only:只读型,缓存不更新,适用于不发生改变的数据,效率最高,事务隔离级别最低

nonstrict-read-write:不严格读写型,缓存不定期更新,适用于变化频率低的数据

Transactional:支持事务,效率最低,事务隔离级别最高,可以防止脏读和不可重复读

7、查询缓存使用

list方法:

第一次使用list查询的时候:得到 :查询结果

1 如果存的是对象,会将对象本身放入一级缓存和二级缓存; 而把sql、id、对象标识放入查询缓存

2 如果存的不是对象,会把结果集放在查询缓存中,不依赖一级二级缓存

再一次使用list查询的时候,会取得查询缓存里面的id去二级缓存中查询,如果查不到,根据id查询数据库

当关闭一级二级缓存,开启查询缓存,会根据id去查询数据库数据,这样就会出现N次问题

iterate方法:

依赖于一级、二级缓存  如果二级缓存关闭,每次都得重新发送sql语句查询数据库

查询对象的时候:

1先查询所有对象id,

2在使用的时候,根据id去一级缓存,二级缓存中去查询实体对象,如果查不到,根据id,一个一个发送sql语句去数据库中查,会出现N+1次问题(如果一级二级缓存关闭,会得到2*(N+1)条语句)

-------------------------------------------------------------------------------------------------------------

Visant

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: