您的位置:首页 > 编程语言 > Java开发

学习hibernate之后的总结,晒一下

2013-07-21 19:30 176 查看
学习了hibernate之后,回顾了一下学习的内容做一些小结。

1.      hibernate为何而来?

以前学习的时候用的是jdbc,能够很好的实现与数据库的连接,但是当数据库中的列名或列的类型改变后,需要对很多代码做修改,当程序需要扩展时也会需要很大的代码
变动。所以hibernate就是为克服jdbc的缺点而来的。

2.      hibernate的优点

(1)      对JDBC进行了非常轻量级的对象封装, 简化了JDBC 繁琐的编码

(2)      将JavaBean对象和数据库的表建立对应关系

(3)      Hibernate使用面向对象的方式设计实体及其关联、继承关系,程序中直接操作这些对象,根本看不到数据库的影子了,甚至数据库中表都不需要手工创建,程序第一
次运行的时候Hibernate就会自动创建好了,非常方便。

3.      如何使用hibernate呢?

Hibernate的使用是借助第三方的jar包来实现的,所以在使用之前要有准备工作。

(1)      创建项目并导入jar包

(2)      创建hibernate配置文件

用于配置数据库连接

运行时所需的各种属性

默认文件名为“hibernate.cfg.xml

(3)      测试连接

4.      hibernate的增删改操作

(1)首先创建实体类,

a.实体类(也称持久化类)是一个带有一些属性的JavaBean类

b.为了通过反射机制来实例化类的对象,我们需要提供一个无参的构造器,所有的实体类都要求有无参的构造器,因为Hibernate需要使用Java反射机制来为你创建对象。

c最后要为实体类实现Java.io.Serializable 接口,以便Hibernate能更好的缓存实体对象。

(2)创建和配置映射文件

a通过实体映射文件,Hibernate知道怎样去加载和存储实体类的对象,知道应该访问数据库里面的哪个表及应该使用表里面的哪些字段

b.在实体类映射文件中,被映射的类必须定义对应数据库表的主键字段的属性。映射文件的<id>元素定义了该属性到数据库表主键字段的映射。

c.主键生成器generator是可选的,它用于指定实体对象的标识符(在表中称之为主键)生成策略。

d.将映射文件的路径信息添加到hibernate.cfg.xml中。

<mappingresource=“***/***/***.hbm.xml" />

(3)数据库的操作

Confuguration->创建SessionFactory—>打开Session->开始一个事务->持久化操作save/update/delete/find->提交事务->关闭Session

代码示例为:

// 1、获取配置

              Configuration cfg = newConfiguration().configure();

              ServiceRegistry serviceRegistry = newServiceRegistryBuilder()

                            .applySettings(cfg.getProperties()).buildServiceRegistry();

                     // 2、创建SessionFactory

                     SessionFactory factory =cfg.buildSessionFactory(serviceRegistry);

              // 3、获取session

              Session session = factory.openSession();

              Transaction tx =session.getTransaction();

              try {

                     // 4、开启事务

                     tx.begin();

                     Seeker seeker = new Seeker();

                     seeker.setEmail("abc@163.com");

                     seeker.setPassword("abc");

                     // 5、保存seeker对象

                     session.save(seeker);

                     //6、提交事务

                     session.getTransaction().commit();

              } catch (Exception e) {

                     tx.rollback();

                     e.printStackTrace();

              } finally {

                     //7、关闭session

                     session.close();

              }

}

 

5.      hibernate的关联性特点

(1)实体之间的关系

关联关系:通过一个对象持有另一个对象的实例

泛化关系:通过对象之间的继承方法来实现

类与类之:间最普遍的关系就是关联关系

(2)除了将实体与表进行映射之外,还要将实体的关联关系与表的关联关系进行映射。我们要关注的是以下三个方面:

l         关联关系在实体中如何体现;

l        
 关联关系在映射文件(hbm.xml)中如果体现;

l         如何完成级联操作。

(4)      对象的导航,关联,一对一,一对多,多对多的关联用hibernate来表示时会更有可读性。

a.单项多对一关联:many的一端应持有one的一端的对象(引用)

映射文件体现多对一

映射文件例:

<hibernate-mapping>

       <classname="org.ijob.bean.Resume" table="ijob_resume">

               <!—省略主键映射及属性映射 -->

               <!--多对一关联 -->

               <many-to-onename="seeker" class="org.ijob.bean.Seeker">       1

                      <columnname="seeker_id"></column>                 2

               </many-to-one>

        </class>

</hibernate-mapping>

注:1、name为属性名,class为“one”端类名

2、外键列列名

b.单向一对多关联:one的一端应持有many端的对象集合

映射文件体现一对多

映射文件例:

<hibernate-mapping>

       <classname="org.ijob.bean.Seeker" table="ijob_seeker">

               <!—省略主键映射及属性映射 -->

               <setname="resumes" >                                               1

                      <keycolumn="seeker_id"></key>                           2

                      <one-to-manyclass="org.ijob.bean.Resume"/>              3

               </set>

</class>

</hibernate-mapping>

代码解析:

1、set集合节点适用于配置一对多关联关系, name属性指定one的一端对应属性名。

2、外键列列名。

3、class属性指定many端的全限定类名。

c.

双向一对多/一对一关联:双向一对多特别简单,就是同时配置了单向的一对多和单向的多对一。

一对一关联是特殊的一对多关联,many的一端是唯一的而不是多个。

book:

<many-to-one name=“type"class=“**" column=“type_id" 
unique="true"/>

type:

<one-to-one name=“book" class=“**"property-ref=“type" />

d.多对多关联

        将多对多转换成两个一对多

        为中间表建立实体类及映射文件,两个端点和中间端分别建立双向一对多关联

如果中间表是联合主键:

<!-- 联合主键 -->

<composite-id>

       <!--同时表达这是外键-->

       <key-many-to-onename=“**” column=“***" class=“***" ></key-many-to-one>

       <key-many-to-onename=“**” column=“**" class=“**" ></key-many-to-one>

</composite-id>

e.cascade与inverse 的使用

Ø         cascade="save-update"意味着对某个对象执行save或update时,其关联对象会自动被持久化。

u       可用于set标签和many-to-one标签

Ø         cascade=“delete”级联删除关联集合

u       用于set标签

Ø         inverse属性用于one-to-many节点,默认为false。

Ø         设置为true,可强制由many的一端来做实际的外键关系维护者,即便代码是从one的一端往集合中添加数据。

6.       使用hibernate可用那些开发过程?

常见开发场景:

•        自上而下:在自上而下的开发过程中,由业务分析和建立领域模型开始,用Java实现实体类。然后构建映射元数据(映射文件),通常是XML文件,也可以是注解,
然后用Hibernate的hbm2ddl工具产生数据库模式(hbm指的是hibernate-mapping,2代表的是to,ddl是数据定义语言)。

•        自下而上:反之,自下而上开发由一个现成的数据库模式开始,可以利用反向工程提取数据库中的元数据。利用hbm2hbmxml可生成XML映射文件;利用hbm2java,
由Hibernate映射元数据生成实体类,利用hbm2dao可生成数据访问对象(DAO)。但是,这种方式生成的代码并不一定能很好地适应于应用的具体要求,有时需要一
些手工的修改。

•        自中间开始:直接编写Hibernate映射文件(XML文件),由它生成Java源码和数据库模式。用手工编写XML映射文件,实体类的信息、数据库模式的信息都需要在这
里面描述,并且在开发过程中不断地更新,这种开发风格只建议经验丰富的Hibernate专家使用。

7.      hibernate的查询操作。

(1)Hibernate 支持两种主要的查询方式

a)        HQL(Hibernate Query Languge,Hibernate 查询语言)查询

                       i.             是一种面向对象的查询语言,其中没有表和字段的概念,只有类、对象和属性的概念

                     ii.             HQL 是应用较为广泛的方式

b)       Criteria 查询

                       i.             又称为“对象查询”,它用面向对象的方式将构造查询的过程做了封装

(2)如何使用HQL

    使用HQL需要四步

     得到Session

      编写HQL语句

      创建Query对象

       Query接口是HQL 查询接口。它提供了各种的查询功能

      执行查询,得到结果

(3)HQL中没有表和字段的概念,只有类、对象和属性的概念

     选择:where 子句指定限定条件(通过与SQL相同的比较操作符指定条件)

     投影:选择出现在结果集中的字段

默认情况下结果为对象数组组成的集合(可使用结果转换器)

      参数绑定:参数绑定有两种方法,分别是利用定位参数和利用命名参数。

String hql = "from Position where name like :name andcreateDay>:minDate";

Query query = sf.openSession().createQuery(hql);

query.setParameter("name", "%Java%");

query.setParameter("minDate", newDate(2013-1900,11,1));

特别注意的是还有一种允许绑定任何hibernate类型实参的一般方法setParameter(),该方法可以自动找出正确的类型

       定位参数:我们也可以在Hibernate中使用定位参数,代码如下:

String hql = "from Position where name like ? and createDay>?";

Queryquery=sf.openSession().createQuery(hql).setParameter(0,aName).setParameter(1,aDate);

请记住Hibernate定位参数是从0开始计数的

      分页:Query接口支持对查询结果进行分页处理,例如:

query.setFirstResult(40);

query.setMaxResults(20);

这两行代码意味着从第41个对象(setFirstResult方法的参数是开始获取对象的行数,从0开始编号)开始,获取接下来的20个对象(setMaxResults方法的参数是获取
对象的数目)。

     分组函数:组函数有count()、min()、max()、sum()和avg(),其含义和SQL中定义的一样。

(4)如何使用Criteria查询

      如果想要查询某个实体类所对应的数据表中所有的内容,可以进行如下的查询。

Criteria criteria = session.createCriteria(**.class);

List users = criteria.list();

       a.使用DetchedCriteria查询

    Criteria实例必须与Session绑定,其生命周期跟随着Session结束而结束。使用Criteria进行查询时,每次都要在运行时动态建立其实例,加入各种查询条件,并且随着
Session的回收,Criteria实例也跟着被回收。

  为了能够重复使用Criteria实例,在Hibernate 3中新增了org.hibernate.criterion.DetchedCriteria

// 先建立DetchedCriteria实例

DetachedCriteria detchedCriteria =DetachedCriteria.forClass(**.class);

…// 省略加入查询条件的代码

Session session = sessionFactory.openSession();

// 绑定Session并返回一个Criteria实例

Criteria criteria = detchedCriteria.getExecutableCriteria(session);

List users = criteria.list();

     org.hibernate.Criteria实际上是个条件附加的容器,如果想要设定查询条件,则要使用org.hibernate.criterion.Restrictions的各种静态方法传回
org.hibernate.criterion.Criterion实例,传回的每个org.hibernate.criterion.Criterion实例代表着一个条件,使用org.hibernate.Criteria的add()方法加入这些条件实例。

例如查询“身高”在160和170之间的求职者,代码如下:

Criteria criteria = getSession().createCriteria(Seeker.class);

criteria.add(Restrictions.gt("bodyHigh", newInteger(160)));//添加条件

criteria.add(Restrictions.lt("bodyHigh", newInteger(170)));//添加条件

List<Seeker> users = criteria.list();

代码中,Restrictions的gt()方法表示大于(great than)条件,而lt()方法表示小于(lessthan)条件。

     我们可以使用org.hibernate.criterion.Order对结果进行排序:

  Criteria criteria =session.createCriteria(Seeker.class);

     criteria.addOrder(Order.asc("birth"));

    List users = criteria.list();

     注意,在加入Order条件时,使用的是addOrder()方法,而不是add()方法,在产生SQL语句时,会使用order by与asc(desc)来进行排序指定。

     Criteria接口的setMaxResults()方法可以限定查询回来的笔数,如果配合setFirstResult()设定查询的起始位置的话,就可以实现简单的分页。

    简单投影

     通过Criteria API的setProjection()方法可以投影一个或多个属性,例如:

List l =getSession().createCriteria(Resume.class)

.setProjection(Projections.id()).list();

(5)加载计划

     Hibernate提供了下列方法从数据库中获取对象:

    1、通过get()或load()方法按照id获取对象。

     
2、从一个已经加载的对象开始,通过系列的get方法访问被关联的对象。

     3、HQL查询获取单个或系列对象。

4、Criteria查询获取单个或系列对象。

  5、原生SQL查询获取单个或系列对象。

    为了加以区别,我们称第一层次的查询目标为“主对象”。现在我们要关注的是主对象及其关联对象的加载计划和加载策略,即数据何时被加载以及数据被怎样加载的问
题。

  涉及到加载计划(何时加载)的关注点有以下几个:

     1、主对象的关联对象何时被加载

     2、主对象的关联集合何时被加载

     3、主对象本身何时被加载

   4、主对象的属性何时被加载

    通过修改对应类的实体映射文件,改变默认的加载计划。

这样做确实能达到上述效果,但我们不建议这样做,因为这样配置之后,不管是否需要关联数据,Hibernate都会加载,这样会造成大量的内存浪费。最好是采用编程
方式在特定情况下进行立即加载(也称热加载),比如我们之前提到的HQL fetch join或者在Criteria查询中设置FetchMode。

     Load加载计划、

如果要禁用代理对象的生成,可在映射文件中,做如下改动:

<class name="……" table="……" lazy="false">

  ...

</class

get和load方式是根据id取得一个记录;

1.从返回结果上对比:
load方式检索不到的话会抛出org.hibernate.ObjectNotFoundException异常
get方法检索不到的话会返回null

2.从检索执行机制上对比: get方法和find方法都是直接从数据库中检索 而load方法的执行则比较复杂首先查找session的persistent Context中是否有缓存,如果有则直接
返回 如果没有则判断是否是lazy,如果不是直接访问数据库检索,查到记录返回,查不到抛出异常 如果是lazy则需要建立代理对象,对象的initialized属性为false,target属
性为null 在访问获得的代理对象的属性时,检索数据库,如果找到记录则把该记录的对象复制到代理对象的target上,并将initialized=true,如果 找不到就抛出异常。   

参考:http://www.cnblogs.com/binjoo/articles/1621254.html

l    需要注意的是,普通属性的默认加载计划是立即加载,这一点我们也可以改变。Hibernate3开始增加了property节点的lazy属性,为特定的属性指定延迟加载计划,以避
免主对象整体加载可能带来的性能浪费,尤其是针对大数据量的属性。

8.      hibernate的高速缓存

(1)hibernate一级缓存

   Hibernate一级缓存的生命周期跟Session的生命周期一样,所以也可以将Hibernate一级缓存称为Session缓存。Hibernate一级缓存是一个强制的高速缓存。

   get()方法会去一级缓存中查找获取数据(又称命中数据),并且将查询结果放置在一级缓存中。load()也一样。

     list()方法会将查询结果放置在一级缓存中,但是它不会去一级缓存中查找获取数据,原因是list()方法不是通过id加载的。

   iterate方法

   Iterator<Seeker> iter =session.createQuery(“from **").iterate();

     该语句只把ID的值放到迭代器中,当遍历的时候,会根据ID的值再去数据库中查。并且该语句会产生N+1次查询。

     session.clear()

     该方法会清除一级缓存。

    session.evict(Object object)

    session.clear()方法是一次性清除一级缓存中的所有数据,而session.evict(Objectobject)方法是清楚一级缓存中指定对象。

数据量比较大的情况下,管理一级缓存的做法一般都是在一定数量的更新或者保存等操作之后,使用flush()和clear()方法将数据同步到数据库并清除一级缓存,从而避免一
次性大量实体数据的缓存导致内存溢出

Session session = getSession();

session.beginTransaction();

for(int i=0;i<10000;i++){ 

Seeker s = new Seeker(); 

s.setName("s" + i); 

session.save(s); //save()、update()方法后的持久态对象会被缓存

if(i%20 == 0) {

       session.flush(); 

       session.clear(); 

}  

}

session.getTransaction().commit();

session.close();

(2)hibernate二级缓存

   二级缓存是一个可选的缓存插件,它由SessionFactory负责管理,所以也常将二级缓存称为SessionFactory缓存。

    由于SessionFactory对象的生命周期和应用程序的整个过程对应,因此二级缓存是进程范围的缓存,可以被线程共享,所以可能存在并发问题,因此需要采用适当的并发
访问策略。

  二级缓存对实体类是可选的,可以在每个类或每个集合的粒度上配置二级缓存。Hibernate的二级缓存策略,是针对于id查询的缓存策略,对于条件查询则毫无作用。

二级缓存的适用条件:

  1、    很少被修改的数据;

     2、    不是很重要的数据;

    3、    不会被并发访问的数据。

二级缓存不适用条件:

   1、    经常被修改的数据;

    2、    财务数据;

     3、    与其他应用共享的数据。

总结:以上是刚学过之后的总结,还没有做到将所学知识吃薄的地步,希望各位大神指教补充!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java hibernate