复习hiernate

 Configuration

Configuration 类负责管理 Hibernate 的配置信息

包括如下内容:1,Hibernate运行的底层信息:数据库的URL、用户名、密码、JDBC驱动类,数据库Dialect,数据库连接池等(对应 hibernate.cfg.xml 文件)。2,持久化类与数据表的映射关系(*.hbm.xml 文件)。

 

创建 Configuration 的两种方式

属性文件(hibernate.properties)
       Configuration cfg = new Configuration();

Xml文件(hibernate.cfg.xml)

加载默认名称的配置文件(hibernate.cfg.xml)
       Configuration cfg = new Configuration().configure();

或加载指定名称的配置文件:
       Configuration cfg = new Configuration().configure(“myhibernate.cfg.xml”);

 SessionFactory

Configuration对象根据当前的配置信息生成 SessionFactory 对象。SessionFactory 对象一旦构造完毕,即被赋予特定的配置信息(SessionFactory 对象中保存了当前的数据库配置信息和所有映射关系以及预定义的SQL语句。同时,SessionFactory还负责维护Hibernate的二级缓存)。 相关代码如下:

   Configuration cfg = new Configuration().configure();

   SessionFactory sessionFactory = cfg.buildSessionFactory();

SessionFactory是线程安全的。

SessionFactory是生成Session的工厂:
       Session session = sessionFactory.openSession();

构造 SessionFactory 很消耗资源,一般情况下一个应用中只初始化一个 SessionFactory 对象。

 

Session(一次与数据库的会话)

Session 是应用程序与数据库之间交互操作的一个单线程对象,是 Hibernate 运作的中心,所有持久化对象必须在 session 的管理下才可以进行持久化操作。此对象的生命周期很短。Session 中有一个缓存,显式执行flush()方法之前,所有的持久层操作的数据都缓存在 session 对象处。(相当于 JDBC 中的 Connection)

持久化类与 Session 关联起来后就具有了持久化的能力。

Session是线程不安全的

Session 类的一些方法:

取得持久化对象的方法: get() load()

持久化对象都得保存,更新和删除:save(),update(),saveOrUpdate(),delete()

开启事务: beginTransaction().

管理 Session 的方法:isOpen(),flush(), clear(), evict(), close()等

 Transaction

代表一次原子操作,它具有数据库事务的概念。所有持久层都应该在事务管理下进行,即使是只读操作。

代表一次原子操作,它具有数据库事务的概念。所有持久层都应该在事务管理下进行,即使是只读操作。
Transaction tx = session.beginTransaction();

常用方法:

commit():提交相关联的session实例

rollback():撤销事务操作

wasCommitted():检查事务是否提交

QueryCriteria接口

都是查询接口,Query实例包装了HQL查询语句,hql是面向对象的,他引用类名及类的属性名,而不是表名和字段名。Criteria接口完全封装了基于字符串形式的查询语句,比Query接口更面向对象,他擅长执行动态查询。

Hibernate的运行过程

Hibernate的运行过程如下:

1、应用程序先调用Configuration类,该类读取Hibernate配置文件及映射文件中的信息,

2、并用这些信息生成一个SessionFactory对象,

3、然后从SessionFactory对象生成一个Session对象,

4、并用Session对象生成Transaction对象;

    A、可通过Session对象的get(),load(),save(),update(),delete()和saveOrUpdate()等方法对PO进行加载、保存、更新、删除、等操作;

    B、在查询的情况下,可通过Session对象生成一个Query对象,然后利用Query对象执行查询操作;如果没有异常,Transaction对象将提交这些操作到数据库中。

 

 动创建表:(hibernate.cfg.xml中配置)

<property name="hbm2ddl.auto">update</property>

create:先删除,再创建

update:如果表不存在就创建,不一样就更新,一样就什么都不做。在开发                   的时候使用较多。

create-drop:初始化时创建表,SessionFactory执行close()时删除 表。

validate:验证表结构是否一致,如果不一致,就抛异常。部署时可以使用

对持久化对象的要求

提供一个无参的构造器。使Hibernate可以使用Constructor.newInstance() 来实例化持久 化类。

提供一个标识属性(identifier property)。通常映射为数据库表的主键字段。如果没有该 属性,一些功能将不起作用,如:Session.saveOrUpdate()。

为类的持久化类的字段声明访问方法(get/set)。Hibernate对JavaBeans风格的属性实行        持久化。

使用非final类。在运行时生成代理是Hibernate的一个重要的功能。如果持久化类没有 实现任何接口,Hibnernate 使用 CGLIB 生成代理。如果使用的是 final 类,则无法生    成CGLIB代理。

重写eqauls()和hashCode()方法。如果需要把持久化类的实例放到Set中(当需要进行    关联映射时),则应该重写这两个方法。

OID

为了在系统中能够找到所需对象,需要为每一个对象分配一个唯一的标识号。在关系数据库中称之为主键,而在对象术语中,则叫做对象标识(Object identifier-OID)。

使用基本数据类型和包装类型的区别

基本数据类型和包装类型对应的hibernate映射类型相同(映射是一样的),例:

propertye (默认值):

表明hibernate通过getXXX和setXXX来访问类属性。推荐使用。提高域模型透明性。

field

hibernate通过java反射机制直接访问类属性。对于没有get与set方法的属性可设置该访问策略。

noop

它映射Java持久化类中不存在的属性,即主要用于HQL(用query接口测试,使用hql语句)中,当数据库中有某列,而实体中不存在的情况。

 

OID,唯一性的标志

关系数据库用主键区分是否是同一条记录。

Hibernate使用OID来建立内存中的对象和数据库中记录的对应关系。对象的OID和数据库的表的主键对应。为保证OID的唯一性,应该让Hibernate来为OID赋值。

 

主键必备条件:

1,不能为null。

2,唯一,不能重复。

3,永远不会改变。

自然主键和代理主键

自然主键:把具有业务含义的字段作为主键叫做自然主键。

代理主键:不具备业务含义的字段,该字段一般取名为“id”。(推荐)

 

关系数据库按主键区分不同记录

 

把主键定义为自动增长类型

在my SQL中,把字段设为auto_increment类型,数据库会自动为主键赋值。

在ms SQL server中,把字段设为identity类型,数据库会自动为主键赋值。

 

oracle从序列(sequence)中获取自动增长的描述符

create sequence seq_customer increment by 2 start with 1

insert into customers  values(seq_customer.curval,’..’)

 

java与Hibernate如何区分对象

Java语言按内存地址(==)或equals()方法区分不同的对象

 

Hibernate中用对象表示符(OID)来区分对象

OID是关系数据库中的主键在java对象模型中的等价物。在运行时,hibernate根据OID来维持java对象和数据库记录的对应关系。

Hibernate使用OID来区分对象,不是equals()方法!所以不重写持久化类的hashCode()与equals()方法Hibernate也可以正确运行(但要放到HashSet等集合中时要注意需要重写这两个方法)。

iD generator元素配置说明

配置示例:

<id name=“id” type=“long” column=“ID”>

      <generator class=“increment” />

</id>

 

 

<id>元素说明:

设定持久化类的 OID 和表的主键的映射,可以有以下属性:

name: 标识持久化类 OID 的属性名 

column: 设置标识属性所映射的数据列的列名(主键字段的名字).

unsaved-value:若设定了该属性, Hibernate 会通过比较持久化类的 OID 值和该属性值来区分当前持久化类的对象是否为临时对象,在Hibernate3中几乎不再需要.

type:指定 Hibernate 映射类型. Hibernate 映射类型是 Java 类型与 SQL 类型的桥梁. 如果没有为某个属性显式设定映射类型, Hibernate 会运用反射机制先识别出持久化类的特定属性的 Java 类型, 然后自动使用与之对应的默认的 Hibernate 映射类型

Java 的基本数据类型和包装类型对应相同的 Hibernate 映射类型. 基本数据类型无法表达 null, 所以对于持久化类的 OID 推荐使用包装类型

 

<generator>元素说明

设定持久化类设定标识符生成器,可以有一个class属性:

class: 指定使用的标识符生成器全限定类名或其缩写名。

 

<generator>元素的class属性可以指定的值说明(主键生成策略)

主键生成器

描述

increment

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

identity

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

sequence

适用于代理主键。Hibernate根据底层数据库序列生成标识符。条件是数据库支持序列。

hilo

适用于代理主键。Hibernate根据hign/low算法生成标识符。Hibernate把特定表的字段作为“hign”值。默认情况下,采用hibernate_unique_key表的next_hi字段。

native

适用于代理主键。根据底层数据库对自动生成表示符的能力来选择identity、sequence、hilo

uuid.hex

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

assigned

适用于自然主键。由java程序负责生成标识符。不能把setID()方法声明为private的。尽量避免使用自然主键。

 

increment

 

increment 标识符生成器由 Hibernate 以递增的方式为代理主键赋值

Hibernate 会先读取表中的主键的最大值,向表中插入记录时, 就在 max(id) 的基础上递增,增量为1。

适用范围:

由于 increment生存标识符机制不依赖于底层数据库系统,因此它适合所有的数据库系统。

适用于只有单个 Hibernate 应用进程访问同一个数据库的场合,在多线程情况下会有问题(线程不安全)。

OID必须为long、int或 short 类型,如果把OID定义为byte类型,在运行时会抛出异常

identity

 

 

identity 标识符生成器由底层数据库来负责生成标识符, 它要求底层数据库把主键定义为自动增长字段类型。

适用范围:

由于 identity 生成标识符的机制依赖于底层数据库系统,因此,要求底层数据库系统必须支持自动增长字段类型。支持自动增长字段类型的数据库包括:DB2、 Mysql、MSSQLServer、Sybase等。

OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常。

sequence

 

 

sequence  标识符生成器利用底层数据库提供的序列来生成标识符.

Hibernate 在持久化一个 News 对象时, 先从底层数据库的 news_seq 序列中获得一个唯一的标识号, 再把它作为主键值

适用范围:

由于 sequence 生成标识符的机制依赖于底层数据库系统的序列,因此,要求底层数据库系统必须支持序列。支持序列的数据库包括:DB2 Oracle 等。

OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常。

hilo

(在hilo中这些关键字都不能修改)

hilo 标识符生成器由 Hibernate 按照一种 high/low 算法*生成标识符, 它从数据库的特定表的字段中获取 high 值.

Hibernate 在持久化一个 News 对象时, 由 Hibernate 负责生成主键值. hilo 标识符生成器在生成标识符时, 需要读取并修改 HI_TABLE 表中的 NEXT_VALUE 值.

适用范围:

由于 hilo 生存标识符机制不依赖于底层数据库系统, 因此它适合所有的数据库系统

OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常

native (在开发中用得最多)

 

native 标识符生成器依据底层数据库对自动生成标识符的支持能力, 来选择使用 identity, sequence 或 hilo 标识符生成器.

适用范围:

由于 native 能根据底层数据库系统的类型, 自动选择合适的标识符生成器, 因此很适合于跨数据库平台开发

OID 必须为 long, int 或 short 类型, 如果把 OID 定义为 byte 类型, 在运行时会抛出异常

  

 Hibernate映射类型

内置映射类型

Hibernate

java

sql

取值范围

integer int

int Integer

INTEGER

4

long

long Long

BIGINT

8

short

short Short

SMALLINT

2

byte

byte Byte

TINYINT

1

float

float Float

FLOAT

4

double

double Double

DOUBLE

8

big_decimal

java.math.BigDecinimal

NUMERIC

8位含2位小数部分

character

char Character String

CHAR(1)

定长字符

string

String

VARCHAR

变长串

boolean

boolean Boolean

BIT

布尔

yes_no

boolean Boolean

CHAR(1)

布尔

true_false

boolean Boolean

CHAR(1)

布尔

 

java时间和日期类性

Hibernate

java

sql

取值范围

date

util.Date sql.Date

DATE

YYYY-MM-DD

time

util.Date sql.Time

TIME

HH:MM:SS

timestamp

util.Date sql.timestamp

TIMESTAMP

YYYYMMDDHHMMSS

calendar

java.util.Calendar

TIMESTAMP

YYYYMMDDHHMMSS

calendar_date

java.util.Calendar

DATE

YYYY-MM-DD

 

大对象类型的映射

Hibernate

java

sql

binary

byte[]

VARBINARY(BLOB)

text

String

CLOB

serializable

实现类

BARBINARY(BLOB)

clob

sql.Clob

CLOB

blob

sql.Blob

BLOB

 

不允许以上类型来定义OID

 

 

(Hibernate Reference3.2.2中有)JDBC 类 java.sql.Clob 和 java.sql.Blob的映射。某些程序可能不适合使用这个类型,因为blob 和 clob 对象可能在一个事务之外是无法重用的。(而且, 驱动程序对这种类型的支持充满着补丁和前后矛盾。)

JDK自带的个别java类的映射类型

Hibernate

java

sql

class

java.lang.Class

VARCHAR

locale

java.util.Locale

VARCHAR

timezone

java.util.TimeZone

VARCHAR

currency

java.util.Currency

VARCHAR

 

集合属性大致有两种:

单纯的集合属性,如像List、Set或数组等集合属性

Map结构的集合属性,每个属性值都有对应的Key映射

 

集合映射的元素大致有如下几种:

list:        用于映射List集合属性

set:               用于映射Set集合属性

map:             用于映射Map集合性

array:             用于映射数组集合属性

bag:              用于映射无序集合

idbag:            用于映射无序集合,但为集合增加逻辑次序

使用集合属性时,一定要使用接口,而不能声明为具体的实现类。

因为经过Session操作后,集合就变成了Hibernate自己的集合实现类

Set

但Set是无序,不可重复的集合。

 

  <class name="Teacher" table="t_teacher">

        <id name="id" column="id" type="int">

        <generator class="native"/>

        </id>

        <property name="name" column="name" type="string" length="20"></property>

           <set name="course" table="t_teacher_course" order-by="caurse DESC">

                  <key column="teacherId"></key>

                  <element type="string" column="caurse" ></element>

           </set>

    </class>

 

order-by 影响是查询顺序(使用较多)

Sort可以影响插入顺序,但是必须是有序集合例如treeset list

测试程序

public class TeacherDao {

       private static SessionFactory  sf;

       static{

              Configuration cfg =  new Configuration();

              cfg.configure();

              cfg.addClass(Teacher.class);

              sf = cfg.buildSessionFactory();

       }

       @Test

       public void save() throws Exception{

              Set<String> set  = new HashSet<String>();

              set.add("java软件开发");

              set.add("C语言");

              set.add("MySql数据库");

             

              Teacher teacher =  new Teacher();

              teacher.setName("张三");

              teacher.setCourse(set);

             

              Session session =  sf.openSession();

              Transaction tc = null  ;

              try {

                     tc  = session.beginTransaction();

                     session.save(teacher);

                     tc.commit();

              } catch (Exception e) {

                     tc.rollback();

                     throw e;

              }finally{

                     session.close();

              }

             

             

       }

       @Test

       public void getById() throws Exception{

              Teacher teacher = null;

              Session session =  sf.openSession();

              Transaction tc = null  ;

              try {

                     tc  = session.beginTransaction();

                     teacher = (Teacher) session.get(Teacher.class, 1);

                     System.out.println(teacher.getId());

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

                     System.out.println(teacher.getCourse().toString());

                     tc.commit();

              } catch (Exception e) {

                     tc.rollback();

                     throw e;

              }finally{

                     session.close();

              }

             

             

       }

      

}

 

 

 

 

注:映射 Set 集合属性时,如果 element 元素包括 not-null = “true” 属性,则集合属性表以关联持久化类的外键和元素列作为联合主键,否则该表没有主键。但 List 集合属性不会,List 集合属性总是以外键列和元素此序列作为联合主键。

在实际应用中,我遇到要求没有顺序不重复的情况很多,所以一般set集合。

 

List是有序集合,可以重复

因此持久化到数据库时必须增加一列来表示集合元素的次序。

集合属性只能以接口声明(当持久化某个实例时, Hibernate 会自动把程序中的集合实现类替换成 Hibernate 自己的集合实现类),因此下面代码中,schools的类型能是List,不能是ArrayList,

 

映射说明

list元素要求用list-index的子元素来映射有序集合的次序列。

集合的属性的值会存放有另外的表中,须以外键关联,用 Key 元素来映射外键列。

当集合元素是基本数据类型及其包装类, 字符串或日期类型时使用 element 来映射集合属性

 

<list name="course" table="t_teacher_course">

                  <key column="teacherId"></key>

                  <list-index column="indx"></list-index>不使用index关键字

                  <element type="string" column="caurse" length="100"></element>

           </list>

 

 

 

测试程序:

 

@Test

       public void save() throws Exception{

              List<String> list = new ArrayList<String>();

              list.add("java软件开发");

              list.add("C语言");

              list.add("MySql数据库");

              Teacher teacher =  new Teacher();

              teacher.setName("张三");

              teacher.setCourse(list);

             

              Session session =  sf.openSession();

              Transaction tc = null  ;

              try {

                     tc  = session.beginTransaction();

                     session.save(teacher);

                     tc.commit();

              } catch (Exception e) {

                     tc.rollback();

                     throw e;

              }finally{

                     session.close();

              }

             

             

       }

 

生成的表及插入的数据

 

 

数组

数组属性的映射和 List 的处理方式基本一致

数组使用 <array> 元素完成完成映射

<array name="course" table="t_teacher_course">

                  <key column="teacherId"></key>

                  <list-index column="indx"></list-index>

                  <element type="string" column="course" length="100"></element>

           </array>

 

代码:

@Test

       public void save() throws Exception{

             

              String[] array = new String[]{"java软件开发1","C语言","MySql数据库"};

              Teacher teacher =  new Teacher();

              teacher.setName("张三");

              teacher.setCourse(array);

             

              Session session =  sf.openSession();

              Transaction tc = null  ;

              try {

                     tc  = session.beginTransaction();

                     session.save(teacher);

                     tc.commit();

              } catch (Exception e) {

                     tc.rollback();

                     throw e;

              }finally{

                     session.close();

              }

             

             

       }

 

 

Bag的特性是:允许重复的元素,但无序。在Java的标准API中并没有提供Bag容器,Hibernate提供自己的Bag实现,允许您将List映射为Bag。

 

bag元素既可以为List集合属性映射,也可以为Collection集合属性映射。

不管是哪种集合属性,使用bag元素都将被映射成无序集合,而集合属性对应的表没有主键。

Bag 元素只需要 key 元素来映射外键列,使用 element 元素来映射集合属性的每个元素。

<bag name="course" table="t_teacher_course">

                  <key column="teacherId"></key>

                  <element type="string" column="caurse" ></element>

           </bag>

 

测试程序:

 

@Test

       public void save() throws Exception{

              List<String> list = new ArrayList<String>();

              list.add("java软件开发");

              list.add("C语言");

              list.add("MySql数据库");

              Teacher teacher =  new Teacher();

              teacher.setName("张三");

              teacher.setCourse(list);

             

              Session session =  sf.openSession();

              Transaction tc = null  ;

              try {

                     tc  = session.beginTransaction();

                     session.save(teacher);

                     tc.commit();

              } catch (Exception e) {

                     tc.rollback();

                     throw e;

              }finally{

                     session.close();

              }

       }

 

 

 

Map不仅需要映射属性值,还需要映射属性Key。

Hibnernate 将以外键列和Key列作为联合主键。

Map集合属性使用map元素映射,该元素需要key和map-key两个子元素

key子元素用于映射外键列,

map-key子元素则用于映射Map集合的Key。

map-key和element元素都必须确定type属性 

 

 

<map name="course" table="t_teacher_course">

                  <key column="teacherId"></key>

                  <map-key type="string" column="kemu" length="100"></map-key>

                  <element type="string" column="course" length="100"></element>

           </map>

 

代码实现:

public void save() throws Exception{

             

              Map<String, String> map = new HashMap<String, String>();

             

              map.put("科目1:", "java软件开发1");

              map.put("科目2:", "C语言");

              Teacher teacher =  new Teacher();

              teacher.setName("张三");

              teacher.setCourse(map);

             

              Session session =  sf.openSession();

              Transaction tc = null  ;

              try {

                     tc  = session.beginTransaction();

                     session.save(teacher);

                     tc.commit();

              } catch (Exception e) {

                     tc.rollback();

                     throw e;

              }finally{

                     session.close();

              }

       }

哦对了忘记说一个事情 我这里面的初始化方法是比较老的那种新的请参见 不同版本的 api

posted @ 2017-08-24 23:49  卫长青  阅读(234)  评论(0编辑  收藏  举报