HIBERNATE 持久化基础

来源:互联网 发布:java的布尔类型 编辑:程序博客网 时间:2024/06/15 23:00

       Hibernate 是一个开放源代码的对象关系映射框架,它通过对 JDBC 进行轻量级的对象封装,使 Java 程序员能够随心所欲地使用面向对象的编程思维来操作数据库。Hibernate 不仅提供了 Java类与数据表之间的映射,而且还提供了数据查询与恢复机制。相对于 JDBC 手工操作数据库而言,Hibernate 大大减少了操作数据库的工作量。另外,Hibernate 能够利用代理模式简化载入类的过程,大大减少了利用 Hibernate QL 从数据库提取数据代码的编写工作量,节约了开发时间及成本。Hibernate 能够与多种 Web 服务器或者应用服务器良好地集成,基本上支持所有流行的数据库服务器。本章主要通过引人持久层及分层结构介绍 Hibernate。

      

Hibernate是一种Java语言下的对象关系映射解决方案。 它是使用GNU宽通用公共许可证发行的自由、开源的软件。它为面向对象的领域模型到传统的关系型数据库的映射,提供了一个使用方便的框架。Hibernate也是目前Java开发中最为流行的数据库持久层框架,现已归JBOSS所有。

它的设计目标是将软件开发人员从大量相同的数据持久层相关编程工作中解放出来。无论是从设计草案还是从一个遗留数据库开始,开发人员都可以采用Hibernate

Hibernate不仅负责从Java类到数据库表的映射(还包括从Java数据类型到SQL数据类型的映射),还提供了面向对象的数据查询检索机制,从而极大地缩短的手动处理SQLJDBC上的开发时间。从上面的介绍中我们看到了两个关键词,对象关系映射(ORM) 和持久化()那么什么是持久化?


1.1 持久化与持久层

1.1.1 什么是持久化

Hibernate是一个优秀的java持久层解决方案,是当今主流的对象-关系映射工具但是何为持久化。

程序运行的时候,有些程序数据保存在内存中,当程序退出后 ,这些数据就不复存在了,所以我们称这些数据为瞬时的(transient)。有些数据在程序退出后,需要进行保存到存储设备上(硬盘,光盘)中,我们称这些数据的状态是持久的(Persistent),持久的数据在程序再次运行的时候是可以恢复、重用的。

持久化就是将有用的数据以某种技术进行保存,以备日后再次取出应用的方法。将内存数据以文件形式保存在永久介质 (磁盘等)中,持久化可以通过将程序数据直接保存成文本文件或者XML格式等手段实现,但平时我们所说的持久化一般是指基于关系型数据库的持久化。

狭义上的对象持久化是指将域对象永久保存至数据库中,而广义上的对象持久化则包括与数据库相关的各种操作。

1保存:将域对象永久保存至数据库中。

2更新:更新数据库中域对象的状态。

3删除:从数据库中删除域对象。

4加载:根据特定的 OID,将域对象由数据库加载至内存。

5查询:根据特定的查询条件,将符合查询条件的一个或多个域对象从数据库加载至内存。

1.1.2  持久层

随着计算机软件的发展,应用程序逐渐由最初的单层结构体系向多层结构体系发展。最初的应用软件只是在大型机上使用单层结构,主要以文件系统的方式存储数据。随着数据库技术的成熟,应用软件由单层向双层发展。在双层应用中,主要包括存放数据的数据库层以及将视图同业务逻辑混合的应用层。例如,一个JSP文件包括网页代码、接收请求与响应的代码以及处理业务逻辑的代码。这种分层方法使程序结构不够清晰,维护十分困难,在大型项目中此缺点尤为突出。因此,三层结构及多层结构应运而生。应用程序的分层体系结构发展如图 1. 1. 2 所示。


三层结构是如今最典型的一种应用软件分层结构,三层分别为:

1表述层:提供与用户交互的界面,主要包括图形用户界面GUI及Web 页面。

2业务逻辑层:主要负责解决、实现特定业务领域的需求。例如,在删除班级时,业务逻辑层首先获取该班级的所有学生信息并删除,然后再删除班级。

3数据层:对应用的业务数据进行存储与管理。例如,在学员管理系统数据库中,对学生、班级等业务数据进行保存。

由三层结构可知,业务逻辑层不仅负责业务逻辑,而且直接访问数据库,提供业务数据的增、删、改、查等功能。为了将数据库访问细节与业务逻辑分开,可以将数据访问独立出来作为持久层。重新分层的软件结构如图 1.1.3示。





当前应用系统设计中,MVC 已是主流系统架构模式,贯穿了整个设计流程。其中,V (View)与 C(Controller)分别指视图与控制器,M (Model)是业务逻辑与数据库逻辑之间的桥梁。持久层作为业务逻辑层中最主要的组件,其设计的好坏直接影响系统的整体表现,是系统中至关重要的一环。


Mvc设计模式与四层应用结构的对应关系见图 1.1.4所示。




所谓“持久层”,是指在系统逻辑层面上专注于实现数据持久化的一个相对独立的领域 (Domain)。持久层是负责向一个或者多个数据存储器中存储 (或者获取)数据的一组类及组件,必须包括一个业务领域的实体模型 (即使只是一个元数据模型)。

持久层封装了数据访问的细节,为业务逻辑层提供面向对象的 APIHibernate就是当今最为流行的一种持久层解决方案。

1.2  ORMHibernate

JDBC是最为常见的一种持久层实现技术,使用JDBC可以较为方便的进行数据库的操作。但是在编写程序的时候,以面向对象的方式处理数据,保存数据的时候却以关系型数据库的方式存储,面向对象的应用系统和关系型数据库之间又存在着严重的不匹配 ,需要在对象和关系型数据库之间进行转换,这个过程极为的繁琐和重复 ,毫无创造性,简直令人崩溃!

hibernate.cfg.xml中配置数据库连接信息和Hibernate的参数如示例1.2所示

<?xml version='1.0' encoding='UTF-8'?><!DOCTYPE hibernate-configuration PUBLIC          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><!-- Generated by MyEclipse Hibernate Tools.                   --><hibernate-configuration><session-factory><!--  自动生成数据库表-->        <property name="hbm2ddl.auto">update</property><!--  方言-->        <property name="dialect">org.hibernate.dialect.OracleDialect</property><!--  数据库url-->  <property name="connection.url">jdbc:oracle:thin:@localhost:1521:forum</property><!--  用户名-->        <property name="connection.username">scott</property><!--  密码-->        <property name="connection.password">tiger</property><!--  数据库驱动--><property name="connection.driver_class">oracle.jdbc.driver.OracleDriver</property><!-- 输出程序运行期间生成的sql语句以供调试 --><property name="show_sql">true</property></session-factory></hibernate-configuration>

Hibernate配置文件的常用属性如表1-1-1所示:

1-1-1  Hibernate配置文件常用属性

属性

描述

hibernate.dialect

一个Hibernate Dialect类名允许Hibernate针对特定的关系数据库生成优化的SQL

hibernate.connection.driver_class

连接数据库的驱动程序类

hibernate.connection.url

连接数据库的 URL

hibernate.connection.username

数据库用户名

hibernate.connection.password

数据库用户密码

hibernate.show_sql

默认取值false,若为true表示在程序运行时将在控制台输出SQL语句,有利于跟踪Hibernate运行状态。通常在应用开发与测试阶段置为true,方便调试测试;在应用发布阶段置为false,减少输出,提高性能。

其他Hibernate常用参数的配置请参考Hibernate包中的参考手册。

Hibernate要求使用者必须将数据库的连接信息放到配置文件中,这样不仅有利于项目的实施,而且降低了项目的风险,当数据库连接信息发生变化,甚至底层数据库发生了变化只需要修改配置文件即可,而无需修改源代码。

4. 创建持久化类

首先定义用户实体类(持久化类)Person.java,代码如示例1.3所示。


public class Person implements Serializable{private int id;//是否被删除private boolean deleted;//创建时间private Date dateCreated;private String account;private String sex;private String name;private String birthday;private String email;//注册时的ipprivate String ipCreated;//最后一次登录时间private Date dateLastActived;//最后一次登录ipprivate String ipLastActived;private String password;//…略getter setter}


5创建映射文件

创建实体类后还需要通知hibernate对象和数据库表 ,对象属性和表字段之间的对应关系,这些映射关系可以在映射文件中加以定义,然后Hibernate才可以根据映射文件工作!映射文件是是Hibernate工作的核心。

从根本上来说,Hibernate对映射文件的名称和路径并无强制要求,可以把所有实体类在一个映射文件中配置,也可以分开多个映射文件进行配置,但原则上我们推荐每个持久对象创建一个映射文件并以class_name.hbm.xml命名并和实体类放置在同一路径下。

在class_name. hbm.xml 中,class_name是实体类的类名。Person.hbm.xml 的内容如示例1.4所示。

示例1.4

<hibernate-mapping package=”com.yourcompany.forum.bean”>    <class name="Person" table="tb_person" catalog="forum">        <id name="id" type="java.lang.Integer">            <column name="id" />          <generator class="sequence"><param name="sequence">SEQ_ID</param> </generator>        </id>        <property name="dateCreated" type="java.sql.Timestamp">            <column name="dateCreated" length="0" />        </property>        <property name="deleted" type="java.lang.Boolean">            <column name="deleted" not-null="true" />        </property>        <property name="account" type="java.lang.String">            <column name="account" />        </property>        <property name="birthday" type="java.lang.String">            <column name="birthday" />        </property>        <property name="dateLastActived" type="java.sql.Timestamp">            <column name="dateLastActived" length="0" />        </property>        <property name="email" type="java.lang.String">            <column name="email" />        </property>        <property name="ipCreated" type="java.lang.String">            <column name="ipCreated" />        </property>        <property name="ipLastActived" type="java.lang.String">            <column name="ipLastActived" />        </property>        <property name="name" type="java.lang.String">            <column name="name" />        </property>        <property name="password" type="java.lang.String">            <column name="password" />        </property>        <property name="sex" type="java.lang.String">            <column name="sex" />        </property>    </class></hibernate-mapping>

其中部分元素的含义如下:

   class元素属性值

1name:对应持久化类名。

2table:对应数据库表名。

3dynamic-update:动态更新,默认为 false。指定用于update 的 SQL将在运行时动态地生成,且只改变更改过的字段。

4dynamic-insert:动态插入。指定用于insert语句的动态生成,并且只插入非空的值。

5select-before-update:执行update之前先执行select语句,若没有修改则不进行 update。这通常会影响性能,但是可以防止对update触发器进行不必要的触发。

6lazy:延迟加载,默认为 true。

id元素

1name:标识属性的名称。

2type:标识Hibernate类型的名称。

3column:对应数据库表的主键字段的名称。

4unsaved-value:其值用于判断对象是否需要保存。

5generator:子元素用于设定标识符生成器。Hibernate提供了多种内置的实现,见表 1-1-2所示。

1-1-2 主键生成策略

标识符生成器

描述

increment

适用于代理主键。由 Hibernate 自动以递增的方式生成标识符,每次增量为 1。

identity

适用于代理主键。由底层数据生成标识符,前提条件是底层数据库支持自动增长字段类型。

sequence

适用于代理主键。Hibernate 根据底层数据庠的序列来生成标识符,前提条件是底层数据库支持序列,通过param子元素指定数据库中使用的序列的名称。

hilo

适用于代理主键。Hibernate 根据 high/low算法生成标识符,将特定表的

字段作为 high值。默认情况下选用 hibernate_ unique_key表 next_hi

字段。

native

适用于代理主键。根据底层数据库对自动生成标识符的支持能力来选择identity、sequence 或者 hilo。

uuid.hex

适用于代理主键。Hibernate 采用 128 位的 UUID算法来生成标识符。UUID算法能够在网络环境中生成唯一的字符串标识符。字符串类型的主键比整数类型的主键占用更多的数据空间,所以这种标识符生成策略并不流行。

assigned

适用于自然主键。由 Java 应用程序负责生成标识符,为了使 Java 应用程序设置OID,不能将 setld ()方法声明为 private 类型。应该尽量避免使用自然主键。

 

property元素映射值类型属性

1name属性:指定持久化类的属性的名称。

2type属性:指定 Hibernate 映射类型。Hibernate映射类型是Java类型与 SQL类型之间的桥梁。

3columm属性:指定与类的属性映射的表的字段名。

4update:默认为 true,指定在update时是否进行更新。

5insert:默认为 true,指定在insert时是否进行插入。

6not-null:默认为 false,指定属性是否为空。

最后一定记得在hibernate.cfg.xml中指定映射文件的位置,这样hibernate才能找得到!

<mapping resource="com/yourcompany/forum/bean/Person.hbm.xml"/>

1.4 使用Hibernate操作数据库

1.4.1 使用Hibernate的七个步骤

经过前面的准备,我们终于可以开始使用Hibernate来操作数据库了,但不用高兴的太早,使用Hibernate需要以下7个步骤, 如图1.1.14所示。



1) 解析并读取Hibernate.cfg.xml

Configuration对象用于读取配置文件并创建 SessionFactory对象,Configuration 的构造方法是将默认路径下的 hibernate.cfg.xml (或 hibernate.properties)配置文件中的配置信息读入内存。如果hibernate.cfg.xml文件不是标准名称或者路径 可以在configure ( )中加以声明,代码如下:

Configuration config = new Configuration();

config.configure();

2)读取并解析映射文件,创建Session Factory, 代码如下:

SessionFactory factory = config.buildSessionFactory();

一个 SessionFactory实例对应一个数据存储源, 可由 SessionFactory 中获得 Session 实例。

SessionFactory包括以下特点:

Ø 线程安全。同一个实例能够被应用的多个线程共享。

Ø 重量级。不能随意创建或销毁。若应用只访问一个数据库,则在初始化时创建一个SessionFactory实例即可;若同时访问多个数据库,则需要为每个数据库创建单独的 SessionFactory实例。

 

3 打开Session。

在 Hibernate应用中,Session接口的使用最为广泛,也称为持久化管理器,提供与持久化相关的操作,如添加、更新、删除、加载及查询对象 ,可以简单理解sessionjdbcConnection的封装。代码如下:

Session session = factory.openSession();

Session包括以下特点:

Ø 非线程安全。在设计软件架构时,应避免多个线程共享同一 Session实例。

Ø 轻量级。即创建与销毁无须消耗过多的资源,可以经常在程序中创建或销毁 Session对象。例如,为每个客户请求分配单独的 Session实例,或者为每个工作单元分配单独的Session实例。

4 Transaction

事务Transaction为应用程序指定以原子操作单元范围的对象。在对数据库进行增加、修改及删除等操作时,必须添加 Transaction,查询操作可选,代码如下:

Transaction tx = session.beginTransaction() ;

5)数据库操作

session.save(person);//或者其他操作

6)提交(回滚)事物

tx.commit();(tx.rollback();)

7)关闭session

session.close();

 

通过以上七步就可以完成对数据库的各种操作,不同之处只在于最终调用session的方法不同而已,所以在项目开发中我们都会使用一个工具类来封装这些重复步骤,代码如示例1.5所示。

示例1.5

public class HibernateUtil {private static Configuration config;private final static  SessionFactory factory;static{config=new Configuration();config.configure();factory = config.buildSessionFactory();}public static Configuration getConfig() {return config;}public static SessionFactory getFactory() {return factory;}public static Session getSession(){return factory.openSession();}}

1.4.2 Hibernate应用

Hibernate 可用于执行增加、查询、修改和删除等操作。

1. 使用hibernate实现添加用户

代码如示例1.6所示。

示例1.6

session = HibernateSessionFactory.getSession();//获取session

tx = session.beginTransaction();//开启事务

session.save(person);

tx.commit();//提交事务

示例中Session 的关闭和事物回滚部分被省略。

 

2. 使用Hibernate实现用户的查询

Hibernate中提供了多种方式来获取数据,现在给大家介绍其中最基本和简单的方式,根据id进行检索:

Ojbect  get(Class clazz,Serializable id)

Ojbect  load(Class clazz,Serializable id)

这两个方法都是使用id进行检索,下面的例子将展示他们的区别。

使用get方法查询用户的代码如示例1.7所示。

示例1.7

Person person = (Person)session.get(Person.class ,1);

System.out.println(person.getName());

本例中只需要一行代码即可完成对象的获取,无需从ResultSet中取得数据进行手工封装。

使用load方法查询用户代码如示例 1.8所示。

示例 1.8

Person person = (Person)session.load(Person.class ,1);

System.out.println(person.getName());

Load方法在指定的id不存在的时候将会抛出异常而get方法不会,但这只是他们的区别之一,更多的区别将会在后续课程中讲解。

 

3.  使用Hibernate实现用户的修改删除

Hibernate中操作都是针对对象的,要修改和删除数据,首先要先获取对象,代码如示例1.9所示。

示例1.9

session = HibernateUtil.getSession();

tx = session.beginTransaction();

Person person = new Person();

person.setId(1);

session.delete(person);

tx.commit();

修改数据的代码如示例1.10所示。

示例1.10

session = HibernateUtil.getSession();

tx = session.beginTransaction();

Person person = (Person)session.get(Person.class,1);

Person.setName(“测试”);

session.update(person);

tx.commit();

通过使用Hibernate进行增删改查操作,我们可以看出Hibernate是面向对象进行操作的,不再需要面对数据库、表、字段等概念。根据面向对象的语义,增删改查方法的参数都是对象而不是主键。以面向对象的思维进行持久化操作是Hibernate的重要理念。

1.5 使用MyEclipse开发Hibernate

MyEclipse提供了简化开发 Hibernate 的功能,大大地提高了开发 Hibernate的效率,减少了映射文件及配置文件的出错率。

使用MyEclipse开发 Hibernate 的步骤如下:

Ø 创建数据库

创建名为forum”的数据库和表tb_person。其中,tb_person表包括12个字段:

id:用户ID,主键 自动增长。

name:用户名称。

password:用户密码。

deleted: 删除标志。

dateCreated: 创建时间

sex: 性别。

birthday:生日。

email 邮件。

ipCreated: 注册时的ip。

dateLastActived: 最后一次登录时间

ipLastActived: 最后一次登录ip。


原创粉丝点击