Hibernate 学习笔记

Hibernate 学习笔记

hibernate的功能是为了满足在数据库和面向对象的软件之间交换数据的需要。

Hibernate的特点:
1,ORM(对象关系映射)功能的框架实现,能用对象的概念来处理关系数据库。
2,功能强大,高效。提供了对象关系映射,对象查询语言HQL,和一套Criteria(标准) API等功能。
3,有丰富的成功案例和文档资料。

Hibernate的核心优点是封装了jdbc。

 

Hibernate的开发步骤:-à搭建开发环境(eclipse)

1.设计持久类(po):先写持久类(包:三部分:域名。项目名称。模块)如:com.tarena.ebank.biz.entity

2.设计映射文件(hbm)

3.构造表结构(scheme)         

4.调用hibernate

 

持久类(pojo  普通java对象):

1.       有空的构造方法(hibernate要new无参数的构造),否则hibernate无法实例化yield对象

2.       所有的属性必须有setter/getter方法

Why  use  OId?

3.持久类最好有一个中性的对象唯一标识符(主键).将对象存到数据库相当于存到表里,存到表里就要有主键。

持久类必须有一个具有唯一标识符的属性,因为数据库中表的id唯一(类中定义一个private Long oid(中性的,后加的,不需要提供set,get方法),对应表中的id)

 

Hbm.xml编码规范:

映射文件中写的是,账户类中信息存储在那个表中,并且是怎样和表对应的:对应关系

               Account类 DB中的表

                  oid      OID

                  acctNO  ACCTNO

                  bal     BALANCE

1.一个映射文件映射一个持久类。

2.映射文件名字与他所映射的持久类的名字保持一致。如Account和Account.hbm.xml

3.映射文件与他所映射的持久类放在同一个包路径下。

 

类对表,属性对字段,对象对记录

类对应表用class来说明,属性对应字段用column来说明。主键对象唯一标识符用id来说明,在id中hibernate要指定一个算法,这里的算法很多。

 

hilo算法特殊:要给一个永久提供唯一id的表,我们必须给表的名和字段名(列名),

<param name="hilo_t"></param>

<param name="column"></param>

实质是传给算法的两个常数

 

如:hilo(hight-low高低为算法)他的原理是:产生很多值去对应oid,而且这些数据都不能重复,用计数器来分配这些数字,因为当拿走一个数字的时候计数器就会加1。如果计数器私有的话,计数器就会归零这样不能保证计数器的不重复性,要解决这个问题需要将计数器放在数据库中公用(在数据库中放一个一行一列的表)。但这样产生的问题是对数据库的访问频率增多,对数据库压力增大。那么怎么做能够降低数据库的压力呢,也就是减少访问次数,提高取回来数字的利用率?Q:在应用程序端也加入一个计数器,从数据库中去一个数字比如说1,应用程序端的计数器就会变为01000000这样的话在应用程序端取一个数字的话计数器机会加1,如去第一次变为01000000,去第二次变为010000001这叫高低位算法,在数据库中建立一个持久计数器(作用:在软件的生命周期中保证全部的数字不重复),在应用程序端建立一个临时计数器(作用:在一个时间段中保证数字不重复)。他们的关系就像名字和姓的关系,持久计数器相当于姓,临时计数器相当于名字

Hilo算法很常用如:电话号码86-020-23878748237,身份证号码等。

Dialect:方言。

 

SessionFactory sf = new Configuration()

              .configure()

              .buildSessionFactory();

sf.openSession();

Hibernate的核心接口一共有5个,分别为:Session、SessionFactory、Transaction、Query和Configuration

这5个核心接口在任何开发中都会用到。通过这些接口,不仅可以对持久化对象进行存取,还能够进行事务控制。

下面对这五的核心接口分别加以介绍。  

(1)Session接口:Session接口负责执行被持久化对象的CRUD操作(CRUD(Create/Read/Update/Delete,CRUD)的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的HttpSession。

这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSesion对象称为用户session。 

(2)SessionFactory接口:SessionFactroy接口负责初始化Hibernate。并负责创建Session对象。

这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为一般情况下,

一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。

多线程中一个线程用一个session,一个session一个事务。

 

(3)Configuration接口:Configuration接口负责配置并启动Hibernate,创建SessionFactory对象。

在Hibernate的启动的过程中,Configuration类的实例首先定位映射文档位置、读取配置,然后创建SessionFactory对象。程序中只需调用一次Configuration 

(4)Transaction接口:Transaction接口负责事务相关的操作。它是可选的,开发人员也可以设计编写自己的底层事务处理代码。

(5)Query和Criteria接口:Query和Criteria接口负责执行各种数据库查询。它可以使用HQL语言或SQL语句两种表达方式。

 

Configuration().configurate()使用名为hibernate.cfg.xml中映射和应用程序资源指定的属性。

Configuration: configure();读配置文件,他返回的是所调用的对象的引用。

Configuration:读配置文件和映射文件,这个函数在一个类中只读一次。

ID生成策略

increment identity sequence hilo seqhilo uuid guid native assigned select foreign

Assigned如果主键值方式没有指定的话就会默认assigned

Sequence:oracle指定的计数器(seqhilo),默认的计数器为hibernate­_sequence。

如果像在mysql中像要产生oracle的主键值就要用到identity。用native可以让hibernate来判断用mysql还是用oracle。

UUID中有128位二进制数,这个数字全世界唯一经过处理后可以变为32位字符串。

重点掌握:native和sequence

String对varchar是字符串在hibernate中的映射

属性对字段---属性的值对字段的类型。值无所谓关键是要说明属性的类型。

Property-type=”java.lang.String”  column-type=”varchar” 简写:type=”string” 说明这个会加快hibernate的运行速度,可读性较高。

 

总结:映射类型是java类型和数据库类型的配对关系

 

单一实体映射(基础)

 

配置文件:

   头信息

   <property name="show_sql">true</property>在第一行,一执行就打印sql

  四个连接数据库的基本信息

   Connection.isolation  2 代表防止涨读,可写可不写

  name="dialect" :方言(—DB类型—)

resource的值就是用到的映射文件的位置

 

注意在hibernate中的异常都是非捕捉异常

 

 

Hibernate中的对象:

对象状态:(一组属性的特定取值)

1. 持久对象的状态-->PO外在的状态    (OOAD中 对象的状态-->PO内在的状态)

(1)Transient 暂时状态: po 和Session无关,数据库中也无该对象的记录

     不受session 管理的,在对象中可表现为持久化对象的主键值没有 save()

Persistent 持久状态: po 和Session有关,数据库中有该对象的记录

      进入了session 的管理,session会自动进行同步。

Detached 游离/脱管态:po和Session无关,数据库中有该对象的记录

      脱离了session 的管理,但数据库有与其对应的记录,所以还可以进入持久化状态。他的主键

注:和Session关系,即Session中有该对象的副本和该对象的引用

       持久化对象: 即就是在数据库中存有其相对应数据的对象,并且在内存中也有这个对象,内部状态和外部状态同步, 这个对象在Session的管理范围内,也就是调用Session.save()方法同步到数据库的对象。对持久态的对象做修改,不调用update方法在提交的时候也会自动更新将数据同步到数据库中。

       临时对象: 即在内存中刚刚创建(new)的对象,还没有同步到数据库,或者是调用Session.delete(),数据库中信息被删除了的对象。

       游离对象: 也就是在数据库中有和该对象向对应的纪录,并且在内存中的也存在该对象,但是不在Session的管理范围之内,例如:在使用load()、get()方法查询到数据并封装为对象之后,将Session实例关闭,则对象由Persistent状态变为Detached状态。就不会在将其改变同步到数据库

在这里强调一下暂态和游离态的区别:暂态与数据库中的记录无关,而游离态与数据库中的记录是相关。持久态的对象调用了delete()方法后尽管数据库中的主键还是存在的,但是它已经跟对象无关了,对象在数据库中的记录已经不存在了。所以持久态对象调用了delete()方法不是游离态,而是暂态   

 

       2. 状态转换图:        

 

Session的get()和load()的区别在于:当要查找的对象数据不存在时,load()方法就是直接抛出异常,而get()方法则返回null值 ,(常考的面试题)

批量操作:相当于JDBC里面的批量更新,调用session.flush(),会刷新缓存,强制执行数据库执行sql语句,将session缓存清空。在做commit之前数据库也会隐藏的执行一次flush(),相当于批量更新

 

1.       持久对象程序再启动的时候还可以再读出来,持久态的对象是自动同步的。

Transient(暂态):对象在内存中已经被创建但还未存入DB。对象刚new出来,在数据库中什么都没有的状态。这个时候很危险,如果掉线或断电数据就会丢失,这是很可怕的。

Persistent(持久态):对象在内存中存在并且存在了数据库中。Session的缓存中有当前对象的克隆体(副本),所以可以实现自动同步。

Detached(游离态):对象已经存在数据库中但是和section无关。Session的缓存中没有当前对象,不能实现同步,这就需要手工同步。持久态变游离态叫脱钩,一般不会用section.close来关闭section,这里仅仅是关闭section而不是删除了section。Section.clear留了section但留了section。Evict()经常用到只删除一个对象。

2.       非持久对象:关机既消失

 

Get() 和load()方法工作原理的不同:get如果查到对象会返回给你,查不到的话返回null,load如果查到对象返回值如果查不到会返回异常。

过程:load不去数据库,造代理对象(看起来像你要的值实际上是空值)

Get会去数据库但是他自己不会产生代理,get方法自身不会产生延迟加载(hibernate的特性),load会产生。

 

load--出缓存找->yes->return object

              ->no->return proxy(代理对象,不去数据库找,因为要是查到而不去用,就什么也不会发生,要是使用,就去数据库找,找不到就抛异常)

   proxy-使用DB中查找->yes-->proxy 填充

                     ->no -->异常

 

load延迟加载,可以提高效率   是Hibernate提高效率的手段,延迟加载通过代理对象来完成的。

get是立即加载

    如何选择load和get?

           我们在迫不得已时(延迟加载不安全时)用get,但延迟加载安全时我们都用load

确定对象已经存在用load,不确定对象是否存在用get

 

hibernate 中持久状态改变时,不会立即被更新到数据库中。这样我们就可以将其优化后更新到数据库中

 

调用flush:代表同步的时刻

when a transaction is committed(隐含的)  当一事务提交

sometimes before a query is executed(隐含的)  有时在执行查询之前

when the application calls session.flush() explicitly(自己调flush)  当应用程序调用Session.flush()的明确

 

Flush的执行:

在事务提交前的一瞬间可能会有某些隐含的flush,

当某些查询之前可能会有某些隐含的flush。

Session.flush()。

 

 

对现存的不满,我们可以改:

设置flushMode 三个常量

:flushMode.AUTO(用)

flushmode.COMMIT(将查询前的覆盖掉)

flushMOde.NEVER:显示调用flush是才会被调用,将flush的权利收回

 

 

Flush mode:FlushMode.AUTO(默认,自动化程度最高,代码的使用对flush没有什么控制) FlushMode.COMMIT(查询前调用),FlushMode.NEVER(除非你调用否则不会被调用,如果像非常精确的控制flush可以考虑用他)。

 

我们和持久对象打交道的session,中有哪些函数可以调用?

 

总结:

1、  transient,persistent,detached 的概念:

transient 暂态:db中无记录入session无关

persistent      db   有记录,与session有关

detached              有               无关

对象状态:持久(怎样持久,持久没有),同步

2、持久对象的管理(状态转换,when,how持久,同步)及工具(session)

3、get、load(延迟加载 proxy)

4、游离态的使用(分布)

5、flush 同步控制和优化

 

 

Batch:批量更新,如果做一个十万次的循环,每存一个对象都会在缓存中存入一个对象,也就说缓存要存放十万个副本这样就会导致缓存溢出。解决这个问题的方法是:每存一批就清空缓存中的前一批。 所有的数据库操作都是在提交之前做的。所以要用flush函数在提交前还没有提交的操作存入数据库中。

 

?  一些复杂的映射(重点):

实体:指账户,订单等。

实体关系:是指这些实体之间的关系。

1.关联关系:

一个类的一个对象A用到了另外一个对象B的某些功能 A use B,B use A

关联关系的内涵是:use,继承关系的内涵是is。A use B,B use A这两种方式是不一样的,他们关系的方向不同

1)如果是A 到B的关系表示为A---àB,如果是B到A的关系表示为A<-----------B,如果是A和B的双向关系A-----B。

2)基数关系(基于数量的关系):一对多,一对一,多对一,多对多。这中映射方式主要考虑数量和方向。基数关系=1:1/1:M/M:1/N:M+方向,

#1:1(单向,双向)

外键的约束是在外键所在的表中定义,在主键所在的表中没有外键信息。

<property name="hbm2ddl.auto">create</property>表示从映射文件自动生成新表,而且会删除旧表

在一对一中关系的维护方在外键方,如果外键方看不到关系则关系会被忽略但不会出异常,主键可以看到他们的关系但他不维护关系;

 

cascade:指明哪些操作会从父对象级联到关联的对象(可选)

property-ref:指定到关联类的一个属性,这个属性将会和表外键相对应。如果没有指定,会使用关联类的主键(可选).

many-to-one:外键是天生的多对一的体现

 

name:属性名。指出many一方的类用哪个属性和one一方的类关联

column:字段名(可选).指出many一方的类对应的数据表用哪个列和one一方的类对应的数据表关联(两表之间存在外键关联);

unique:允许产生外键列唯一约束的数据库定义语言(DDL)(可选)

constrained="true"给hibernate说明这里的one-to-one不是主键是外键

 

 

 

3)组件关系:单一组件,组件集合。组件关系主要考虑强度

 

2.继承关系(有三种方案)

你可能感兴趣的:(Hibernate)