Hibernate in Action

1.什么是Hibernate?
    Hibernate (开放源代码的对象关系映射框架)

Hibernate是一个开放源代码的对象关系映射框架,它对JDBC进行了非常轻量级的对象封装,它将POJO与数据库表建立映射关系,是一个全自动的orm框架,hibernate可以自动生成SQL语句,自动执行,使得Java程序员可以随心所欲的使用对象编程思维来操纵数据库。 Hibernate可以应用在任何使用JDBC的场合,既可以在Java的客户端程序使用,也可以在Servlet/JSP的Web应用中使用,最具革命意义的是,Hibernate可以在应用EJB的J2EE架构中取代CMP,完成数据持久化的重任。

语言特点

    将对数据库的操作转换为对象Java对象的操作,从而简化开发。通过修改一个“持久化”对象的属性从而修改数据库表中对应的记录数据。
    提供线程和进程两个级别的缓存提升应用程序性能。
    有丰富的映射方式将Java对象之间的关系转换为数据库表之间的关系。
    屏蔽不同数据库实现之间的差异。在Hibernate中只需要通过“方言”的形式指定当前使用的数据库,就可以根据底层数据库的实际情况生成适合的SQL语句。
    非侵入式:Hibernate不要求持久化类实现任何接口或继承任何类,POJO即可。

核心API

Hibernate的API一共有6个,分别为:Session、SessionFactory、Transaction、Query、Criteria和Configuration。通过这些接口,可以对持久化对象进行存取、事务控制。
Session
Session接口负责执行被持久化对象的CRUD操作(CRUD的任务是完成与数据库的交流,包含了很多常见的SQL语句)。但需要注意的是Session对象是非线程安全的。同时,Hibernate的session不同于JSP应用中的HttpSession。这里当使用session这个术语时,其实指的是Hibernate中的session,而以后会将HttpSession对象称为用户session。
SessionFactory
SessionFactory接口负责初始化Hibernate。它充当数据存储源的代理,并负责创建Session对象。这里用到了工厂模式。需要注意的是SessionFactory并不是轻量级的,因为**一般情况下,一个项目通常只需要一个SessionFactory就够,当需要操作多个数据库时,可以为每个数据库指定一个SessionFactory。**

Transaction
Transaction 接口是一个可选的API,可以选择不使用这个接口,取而代之的是Hibernate 的设计者自己写的底层事务处理代码。 Transaction 接口是对实际事务实现的一个抽象,这些实现包括JDBC的事务、JTA 中的UserTransaction、甚至可以是CORBA 事务。之所以这样设计是能让开发者能够使用一个统一事务的操作界面,使得自己的项目可以在不同的环境和容器之间方便地移植。
Query
Query接口让你方便地对数据库及持久对象进行查询,它可以有两种表达方式:HQL语言或本地数据库的SQL语句。Query经常被用来绑定查询参数、限制查询记录数量,并最终执行查询操作。
Criteria
Criteria接口与Query接口非常类似,允许创建并执行面向对象的标准化查询。值得注意的是Criteria接口也是轻量级的,它不能在Session之外使用。
Configuration
Configuration 类的作用是对Hibernate 进行配置,以及对它进行启动。在Hibernate 的启动过程中,Configuration 类的实例首先定位映射文档的位置,读取这些配置,然后创建一个SessionFactory对象。虽然Configuration 类在整个Hibernate 项目中只扮演着一个很小的角色,但它是启动hibernate 时所遇到的第一个对象。

主键介绍

Assigned
Assigned方式由用户生成主键值,并且要在save()之前指定否则会抛出异常
特点:主键的生成值完全由用户决定,与底层数据库无关。用户需要维护主键值,在调用session.save()之前要指定主键值。
Hilo
Hilo使用高低位算法生成主键,高低位算法使用一个高位值和一个低位值,然后把算法得到的两个值拼接起来作为数据库中的唯一主键。Hilo方式需要额外的数据库表和字段提供高位值来源。默认情况下使用的表是
hibernate_unique_key,默认字段叫作next_hi。next_hi必须有一条记录否则会出现错误。
特点:需要额外的数据库表的支持,能保证同一个数据库中主键的唯一性,但不能保证多个数据库之间主键的唯一性。Hilo主键生成方式由Hibernate 维护,所以Hilo方式与底层数据库无关,但不应该手动修改hi/lo算法使用的表的值,否则会引起主键重复的异常。
Increment
Increment方式对主键值采取自动增长的方式生成新的主键值,但要求底层数据库的主键类型为long,int等数值型。主键按数值顺序递增,增量为1。
/*特点:由Hibernate本身维护,适用于所有的数据库,不适合多进程并发更新数据库,适合单一进程访问数据库。不能用于群集环境。*/
Identity
Identity方式根据底层数据库,来支持自动增长,不同的数据库用不同的主键增长方式。
特点:与底层数据库有关,要求数据库支持Identity,如MySQl中是auto_increment, SQL Server 中是Identity,支持的数据库有MySql、SQL Server、DB2、Sybase和HypersonicSQL。 Identity无需Hibernate和用户的干涉,使用较为方便,但不便于在不同的数据库之间移植程序。
Sequence
Sequence需要底层数据库支持Sequence方式,例如Oracle数据库等
特点:需要底层数据库的支持序列,支持序列的数据库有DB2、PostgreSql、Oracle、SAPDb等在不同数据库之间移植程序,特别从支持序列的数据库移植到不支持序列的数据库需要修改配置文件。
**Native
Native主键生成方式会根据不同的底层数据库自动选择Identity、Sequence、Hilo主键生成方式
特点:根据不同的底层数据库采用不同的主键生成方式。由于Hibernate会根据底层数据库采用不同的映射方式,因此便于程序移植,项目中如果用到多个数据库时,可以使用这种方式。**

UUID
UUID使用128位UUID算法生成主键,能够保证网络环境下的主键唯一性,也就能够保证在不同数据库及不同服务器下主键的唯一性。
特点:能够保证数据库中的主键唯一性,生成的主键占用比较多的存贮空间
Foreign GUID
Foreign用于一对一关系中。GUID主键生成方式使用了一种特殊算法,保证生成主键的唯一性,支持SQL Server和MySQL

 

Hibernate 配置文件的配置项

<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

<property name="dataSource" ref="dataSource"/>

<!-- hibernate自身配置 -->

<property name="hibernateProperties">

<props>

<!-- javaEE6 项目去验证 -->

<prop key="javax.persistence.validation.mode">none</prop>

<! -- 数据库方言 -->

<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>

<!--  输出sql -->

<prop key="hibernate.show_sql">true</prop>

<prop key="hibernate.format_sql">true</prop>

<! --

hbm2ddl.auto:该属性可帮助程序员实现正向工程,即由java代码盛世数据库脚本,进而生成具体的表结构。取值:create,create-drop,update,validate

create:会根据 .hbm.xml文件来生成数据库表,但是每次运行都会删除上一次表,重新生成新表,即使表结构,表数据没有任何改变。

create-drop:会根据 .hbm.xml文件来生成数据库表,但是SessionFactory一关闭,就自动删除表及数据

update:最常见的属性值,也会根据 .hbm.xml文件来生成数据库表,但若 .hbm.xml 文件和数据库表中对应的表结构不同,Hibernate将更新数据表结构,但不会删除已有的行和列。

validate:会和数据库中的表进行比较,若 .hbm.xml文件中的列在数据表中不存在,则抛出异常

-->

<prop key="hibernate.hbm2ddl.auto">update</prop>

<!-- 配置缓存相关 -->

<!-- 启用二级缓存 -->

<prop key="hibernate.cache.use_second_level_cache">true</prop>

<!-- 启用查询缓存 -->

<prop key="hibernate.cache.use_query_cache">true</prop>

<!-- 缓存提供者 -->

<prop key="hibernate.cache.provider_class">org.hibernate.cache.EhCacheProvider</prop>

</props>

</property>

<!-- 映射文件注册 -->

<property name="mappingDirectoryLocations">

<list>

<value>classpath:com/zpark/shop/hbm</value>

</list>

</property>

</bean>

 

Hibernate中的Session详解

Session缓存

session缓存是由一系列的Java集合构成的。当一个对象被加入到Session缓存中,这个对象的引用就加入到了java的集合中,以后即使应用程序中的引用变量不再引用该对象,只要Session缓存不被清空,这个对象一直处于生命周期中。

站在持久化的角度,Hibernate把对象分为4种状态:持久化状态,临时状态,游离状态,删除状态。session的特定方法能使对象从一个状态转换到另一个状态。

  Session缓存的作用

  1)减少访问数据库的频率。

  2)保证缓存中的对象与数据库中的相关记录保持同步。

  Session清理缓存的时机:

1)当调用Transaction的commit()方法时,commit()方法先清理缓存(前提是FlushMode.COMMIT/AUTO),然后再向数据库提交事务。

  2)当应用程序调用Session的find()或者iterate()时,如果缓存中的持久化对象的属性发生了变化,就会先清理缓存,以保证查询结果能反映持久化对象的最新状态。

  3)当应用程序显示调用Session的flush()方法的时候。

flush:使数据表中的记录和session缓存中的对象状态保持一直,为了保持一致,则可能会发送对应的sql语句,若sesion缓存中的对象与数据库中的记录一致,则不发送update语句,若不一致则发送update语句

1.调用Transaction的commit()方法中:先调用session的flush方法,再提交事务

2.flush()方法可能会发送sql语句,但不会提交事务。

3.注意:在未提交事务或显示调用session.flush()方法之前,也有可能进行flush()操作

1).执行HQL或QBC查询,会先进行flush()操作,以得到数据表的最新记录。

2).若数据的id是由底层数据库使用自增的方式生成的,则在调用save()方法时,就会立即发送INSERT语句,因为save()方法后必须保证对象的id时存在的!

Session清理模式执行清理缓存操作的时间点:

数据库的隔离级别

对于同时运行的多个事务,当这些事务访问i数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:

脏读:对于两个事务T1,T2,T1读取了已经被T2更新但还有提交的字段之后,若T2回滚,T1读取的内容就是临时且无效的。

不可重复读:对于两个事务T1,T2,T1读取了一个字段,然后T2更新了该字段之后,T1再次读取同一个字段,值就不同了;

幻读:对于两个事务T1,T2,T1从一个表中读取了一个字段,然后T2在该表中插入了一些新的行之后,如果T1再次读取同一个表,就会多出几行;

数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题

一个事务与其他事务隔离的程度称为隔离级别,数据库规定了多种事务隔离级别,不同的隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性就越弱;

refresh()会强制发送select语句,以使session缓存中对象的状态和数据表中对应的记录保持一致!

 

Session接口

 

Session接口是hibernate向应用程序提供的操纵数据库的最主要的接口,它提供了基本的保存,更新,删除和查询的方法。

1.save(): 把一个临时对象加入到缓存中,是它变成持久化对象

-->选用映射文件指定的主键生成器为持久化对象分配唯一的OID

-->计划一条insert语句,把参数对象当前的属性值组装到insert语句中,但是save()方法并不立即执行SQL insert语句,只有当Session清理缓存时候才会执行。

-->如果在save()方法之后,又修改了持久化对象的属性,会使得Session在清理缓存的时候额外执行SQL update语句。

注意:save()方法是用来持久化一个临时对象的!

  如果将一个持久化对象传给save()方法将不会执行任何操作,多余的步骤

  如果将一个游离态对象传给save()方法,session会将它当作临时对象来处理,再次向数据库中插入一条记录,不符合业务需求!

2.update():把Customer对象重新加入到Session缓存中,使之变为持久化对象。

   --->计划一条update语句,只有在清理缓存的时候才会执行,并且在执行的时候才会把参数对象中的属性值组装到update语句中。

注意:update()是将一个游离对象转变为持久化对象的。

  只要通过update()方法使游离对象被一个session关联,即使没有修改参数对象的任何属性,Session在清理缓存的时候也会执行由update方法计划的Update语句。

3.saveOrUpdate():同时包含了save()与update()方法的功能,如果传入的参数是临时对象,调用save方法,如果参入参数是游离对象,调用update()方法,如果传入的是持久化对象,直接返回。

4.load()/get(): 都会根据给定的OID从数据库中加载一个持久化对象,区别在于,当数据库中不存在与OID对应的记录时,load()方法会抛出ObjectNotFoundException异常,而get()方法返回null.

5.delete():用于从数据库中删除与参数对象对应的记录,如果传入的参数是持久化对象,Session就计划执行一个delete语句,如果传入的参数是游离对象,先使游离对象被Session关联,使它变为持久化对象,然后计划一个delete语句,在清理缓存的时候执行。

6.evict():从缓存中清除参数指定的持久化对象。

  适用场合:不希望Session继续按照该对象的状态改变来同步更新数据库。

    在批量更新或批量删除的场合,当更新或者删除一个对象后,及时释放该对象占用的内存。当然批量操作优先考虑JDBC.

7.clear():清空缓存中所有持久化对象。

 

 

转载于:https://my.oschina.net/ruanjun/blog/1550407

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值