读书笔记:Hibernate基本用法(JavaEE 企业应用实战,3rd)

李刚的书写的很晦涩,不知道那么多人捧是为什么……对照着官方Document看了一下,基本就是把那文档翻译过来了,只不过裁剪了一些废话。

但是很多翻译的都不明白。

以下是结合书中第五章《Hibernate基本用法》和官方文档中所述,学习所得。

1、Hibernate的第一个例子。

使用Hibernate ORM框架开发的程序一般是四个部分组成:

  • POJO(代表一个实体)
  • 实体的hbm映射
  • Hibernate总体配置(数据库连接等)
  • Java代码,用于驱动ORM。

POJO类

符合Java的POJO规范,必须有无参数的构造函数,可选有setter和getter,不是必须的,因为Hibernate可以用反射搞定。

hbm映射文件

该文件指名POJO和数据库的映射关系:POJO中哪些域,要对应到,数据库的哪些字段、表中。

文件命名规范:类名.hbm.xml,例如这里是News.hbm.xml。其实可以多个Class的映射关系写到一个文件中,但不便于维护,因此不推荐。

News.hbm.xml

从上述文件可以很清楚的看到:

  • 一个POJO对应一个<class>配置标签,name与类全名保持一致。
  • 普通(Java8大内置类型)可以用<id>或<property>表示
  • <id>是数据库中的主键(物理主键,一般无BI或逻辑含义。)
  • <id>或<property>的name属性为POJO的属性名。
  • 默认的,数据库中列名与name一致,如果想更改,可以指定column树形,或者在<property>下追加<column>孩子结点。
  • <id>下的<generator>可以指定该字段自动递增的方式,这个是数据库中很常见的功能了。

Hibernate配置文件

Hibernate配置文件的默认文件名是hibernate.cfg.xml,当类Configuration对象调用configure()方法时,会自动加载这个配置文件。

上述配置由4部分组成:

  • 数据库连接配置:hibernate.connection.*
  • 数据库方言:dialect,是否要自动创建数据库中的表:hbm2ddl.auto,如果是update,将自动创建,Session结束时不删除表。如果是create,每次执行时会重新建一个新表(在新建之前删除)。如果是create-drop,自动创建,且session结束后删除表。
  • c3p0,Hibernate推荐使用的数据库连接池之一,也可以用proxool。
  • <mapping>标签指定了引入哪些之前定义的POJO映射文件类,例如这里,我们引入了News.hbm.xml。

除了这些,在hibernate.cfg.xml中,还可以指定Cache、Transection(事务)、调试、抓取量等选项。

操作代码:

依赖的其他lib有:

c3p0-0.9.1.jar
hibernate3.jar
slf4j-api-1.6.1.jar
slf4j-nop-1.6.1.jar
dom4j-1.6.1.jar
hibernate-jpa-2.0-api-1.0.1.Final.jar
mysql-connector-java-5.1.22-bin.jar
commons-collections-3.1.jar
antlr-2.7.6.jar
javassist-3.12.0.GA.jar
jta-1.1.jar

具体代码

2、Hibernate基本结构。

Hibernate的核心目的:将用户从原始的JDBC代码堆砌中解放出来,以面向对象的方式操纵数据库。

Hibernate的几大关键对象:

  • SessionFactory:线程安全,一个应用一个就够,它是Session的工厂。
  • Session:单线程(非线程安全),底层对应一个JDBC连接,业务逻辑的数据持久化、访问都需要通过Session完成。它是Transaction的工厂。
  • Transaction:事务,对应数据库中的原子操作。Hibernate的事务集成了JDBC、JTA、COBRA的事务概念(后几个都是在分布式系统中的事务)。
  • TransactionFactory:生成Transaction的实际工厂,在Hibernate中被内部封装了,一般Session.beginTransaction()就可以了,无须直接访问这个类。
  • ConnectionProvider:在Hibernate中的地位,类似于JDBC中的DriverManager,实际也是对它的封装。
  • 持久化对象=POJO+与之关联(管理它的)Session。

此外,持久化对象的状态非常重要,主要有三个:

  • 瞬态:刚new出来的,还没有与Session关联。
  • 持久化状态:通过Sesision的save、load等,与Session绑定在一起的状态,此时可进行持久化或读取操作。
  • 脱管:注意是不是托,当持久化状态的对象,Session关闭,或通过API解除绑定后,变成这个状态。

3、hibernate.cfg.xml(Hibernate配置文件)详解

暂略

4、深入持久化对象

暂略

5、XXX.hbm.xml(Hibernate映射文件)详解

映射文件的结构一般如下:

根<hibernate-mapping>的重要属性有:

  • schema、catalog:指定schema、catalog,不知道做什么用的……
  • default-cascade:级联风格,默认为none,不级联。
  • default-access:property,需要getter和setter方法访问属性,默认是这个。field,通过反射,直接获取属性名。
  • default-lazy:控制延迟加载,默认true,也建议不关闭。
  • package:指定包名,用于本文件中没有写完整包名路径的类。
  • auto-import:是否允许使用非全限定类名,和上面的package共用。

一个<hibernate-mapping>元素可以对应多个<class>元素,即一个文件中可以配置多个持久化类。但一般建议每个类一个文件,存在Class同目录下、命名为类名.hbm.xml,方便管理与后期维护。

<class>元素的可选属性为:

  • table:存储这类持久化对象的表名
  • discriminator-value:当有子类继承<subclass>时,可以用此属性区分父类还是子类。
  • mutable:持久化对象是否可改变,true或false。
  • proxy:用于替换lazy-load时的代理类。
  • dynamic-update、dynamic-insert:指定用于插入记录的insert、update语句是否在运行时动态生成。默认为false,如果开启true,生成sql时间可能会延长。如果开启,建议同时配合version的锁策略。
  • select-before-update:很明显了,在更新之前是否需要select,默认为false,即update总执行。如果设置成true,则会先select,并比对数据库中状态与POJO是否一致,一样就不更新了。
  • polumorphism:当使用<union-subclass>的继承类时配置。
  • where:附加过滤条件,不管是load()还是get(),只要试图加载,都会应用这个条件。
  • batch-size:抓取实例时,每批数据抓取数量。
  • optimistic-lock:乐观锁定策略,默认version。
  • subselect:映射只读实体,类似视图。

<class>下面的孩子,常见的为<id>和<property>,前者对应数据库中的主键,后者为非主键的普通属性。

映射(数据库)主键

如上所示,<id>表示了一个主键,name为主键在POJO中的属性名,column是主键在DB中的列名。type是主键类型。

<id>内置的generator是自动生成主键的策略。生成策略分为很多种:increment、identity、sequence、hilo、甚至uuid等。

但若采用uuid,POJO的字段类型需要为String。

映射(数据库)普通属性

如下是3个比较典型的普通属性配置:

  • name:POJO中的属性名
  • type:字段类型类型
  • column:在DB中的列名
  • not-null:同数据库
  • index:指定该字段含索引、及索引的名称。
  • unique_key:配合index,若指定了,则将创建uniq-key-index索引。
  • length、scale、precision:当为字符串时,length控制CHAR长度。scale和precision则为double类型的精度。
  • formula:则该属性只不写DB只读,且读时由formula指定的SQL语句生成,比如这里拼接了两个字段。注意参数由不加数据库名约束的id,在Load时由同类型的传入,在这里参数为=id。此外,sql必须用()括起来!!

对应的读取驱动如下:

自动生成字段

Hibernate也支持由数据库自动生成字段。

首先,要将字段的generated设置成insert或者always,这将使得通过Hibernate执行了update或者insert后,自动触发select,以映射最新的数据到POJO中,但此generated并不管怎么自动生成。

具体的生成方式需要额外指定,例如可以是触发器,也可以是时间戳这种default值:通过子column,设置sql-type和default值,如上所示。

注意,一旦使用column,则必须指明sql-type,否则可能无法创建数据库。

6、映射集合属性

一个POJO中,可能出现集合属性,例如Map、List等。对应的含义可能是课程的成绩、一个人的昵称(假设有很多个,需要用List存~)

Hibernate支持了很多集合属性的映射,其tag对应如下:

  • <list>/<set>/<map>/<array>:对应Java内置的List、Set、Map接口和数组。
  • <bag>、<idbag>:实际对应了Java内置的Collection。

集合属性其实也是一个属性,和上面POJO的lastname等一样,因此继承了name、schema、lazy等属性,同时又有以下不同点:

  • table:因为需要存储在另一个表里。
  • cascade:指定是否级联。
  • order-by:是否排序,可选xxx asc/desc
  • 子标签<key>:在table中,需要有一个物理主键(例如自增的id,同News中的id)。
  • 对于list、map、array,除了上述物理主键,还需要有对应Collection的逻辑主键,例如Map的Key、List、Array的下标。分别用<map-key>、<list-index>等指定。

特别注意:映射Collection属性时,属性必须使用接口,如Set、List。而new时候才能使用ArrayList等。

映射List属性

假设Person中有一个属性,List<String>,如下:

一般来说,这个List要单独放在另外一张表中的,所以map文件如下:

如上所示,Person存在tbl_person表中,School存在了tbl_school表中,两个表通过p_id这个外键连接在一起。

school表中,s_order是对应的s_name在schools的List中的下标。同时,该表是联合主键:p_id和s_order。因此,可以保证不同Person之间的school名即使有冲突,也可以正常存放,且顺序不会乱。

两个表的结构如下:

tbl_person:

tbl_school:

最后看驱动:

映射数组属性

映射数组属性和List很相似,除了<list>换成了<array>,连下标映射字段都沿用了<list-index>

POJO如下:

Person.hbm.xml:

驱动:

 映射Set属性

Set内无次序,但是仍然需要保证主键约束:按照Set的语义,每一个p_id对应的p_name,不能重复。

注意:p_name必须是not-null的,否则无法作为主键!

做好后的数据库结构如下,p_id和s_name联合主键:

代码如下:

映射Collection属性

是的,这里指的是java.util.Collection,它对应的hbm标签是<bag>。

 

 

Leave a Reply

Your email address will not be published.