hibernate 实战(第二版)
第4章映射持久化类
本章内容
本章介绍基础的映射选项,阐述类和属性如何被映射到表和列。我们介绍和讨论如何处理数据库同一性和主键,
以及各种其他元数据设置如何被 用来定制Hibernate加载和存储对象的方式。所有映射示例都以hibernate的
原生XML格式完成,且并列使用JPA注解和XML描述符。我们还深入探讨细粒度领域模型的映射,以及如何映射
属性和嵌入的组件。
1细粒度的领域建模
Hibernate的一个主要目标是支持细粒度的领域建模,过去我们把它分离出来作为富领域模型最重要的必要条件。
这是我们使用POJO的一个原因,粗略的说,细粒度意味着类比表要多。
2映射带有同一性的实体
持久化使事情变得复杂起来。利用对象/关系持久化,持久化对象是数据库表的一个特定行的内存表示。连同Java同一性(内存位置)
和对象等同性一起,你还要选择数据库同一性(在持久化数据库仓库中的位置)。
1、如果对象在JVM中占据着相同的内存位置,他们就是同一的。这可以通过使用==操作符进行检查。这个概念称作对象同一性。
2、如果对象有着相同的值,他们就是相等的,如equals方法定义的一样。不显示覆盖这个方法的类,继承了由Object定义的实现,
他比较对象同一性。这个概念称作等同性。
3、如果存储在一个关系数据库中的对象标识相同的行,或者他们共享相同的表和主键值,他们就是同一的。这个概念称作数据库同一性。
试验证明在同一个EntityManager里面,同一个id的对象是 == 的,也是同一个对象。
通常声明setId()方法为私有,并让hibernate生成和设置标示符值。
生成器名称 JPA GenerationType 选项 描述
Native AUTO Native同一性生成器挑选其他同一性生成器如identity、sequence或者hilo,取决于底层数据库的能力。使用这个生成器保证映射元数据可以移植到不同的数据库管理器
Identity IDENTITY 这个生成器支持DB2、Mysql、MS SQL Server、Sybase和HypersonicSQL中的同一性列。返回的标示符类型为long、short或者int。
Sequence SEQUENCE Sequence、
Parameters 这个生成器在DB2、PostgreSQL、Oracle、SAPDB或者Mckoi中创建一个序列:或者使用InterBase中的一个生成器。返回的标示符类型为long、short或者int。如果创建序列的其他设置要被添加到DDL,就使用sequence选择给序列定义一个目标名称(默认是hibernate_sequence)和paramters
3类映射选项
Hibernate生成update语句,会更新所有的列。
在有些情况下,例如包含几百列的一个遗留表,在该表中,即使最简单的操作的sql语句也很大,必须关闭这个启动时
的sql生成,并切换到运行时生成的动态语句。当大量实体时,也会影响启动时间,因为hibernate必须为CURD提前生
成所有SQL语句:
区别就是:
Hibernate: insert into USER (user_Name) values (?)
Hibernate: insert into USER (user_Name, password) values (?, ?)
配置:
使实体不可变:
一个特定类的实例可以是不可变的。
效果:
没有sql打印,也没有报错,也就是忽略了更新操作
配置:
用引号把SQL标示符括起来。
·实体数据库命名约定;
配置:<class name="BankAccount"> 生成表明:pa_bank_account
配置:<class name="BankAccount" table="BankAccount"> 生成表明:pa_bank_account (书中说的是错误的)
配置:<class name="BankAccount" table="BANK_ACCOUNT"> 生成表明:pa_bank_account
4细粒度的模型和映射
但是最少包括not-null属性,因为还没有提交给数据库之前会报告空指针异常。(看看save源码都做了些什么)
被注解的实体从强制的@Id注解的位置继承默认的访问策略。(如果@Id已经在字段中而不是获取方法上声明,
那么所有其他的属性 映射注解也必须在字段中)
@Transient
声明此字段不被 映射到数据库中
指定注解位置:
会报的错误:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: cn.partner4java.jpa.bean.TestBean1
关联属性:
一些字段可以不存在于表中,而是关联的一些属性,比如关联显示每个一个货物的所有出价平均值:
那么这个字段也不会出现在插入和更改SQL中
前面我们说过可以使一个实体不可变(mutable="false"),那么也可以使一个字段不可变,忽略变动:
在此基础上来实现:生成的默认属性:
就是有一些字段,比如是利用触发器生成的,也就是不是我们这里完成的,是第三方触发完成,那么当你插入或者更新完之后,又想获得的对象包括这个触发值,那么可以:
默认值(有两点是必须注意的,一个是必须是null,一个是会引起为null):
private Integer age;//*注意这里必须给Integer,因为int类型是有默认值0的 (也就是插入对象的这个属性的值必须是null)
(DLL: `age` int(11) default '1',)
*你还必须开启动态的插入更新语句的生成(@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true),以便包括默认值的列不会出现在每个语句中,
否则将插入的是null。
映射组件:
这两个字段就会包含到homeAddress属性的类里面。
xml:
第4章映射持久化类
本章内容
本章介绍基础的映射选项,阐述类和属性如何被映射到表和列。我们介绍和讨论如何处理数据库同一性和主键,
以及各种其他元数据设置如何被 用来定制Hibernate加载和存储对象的方式。所有映射示例都以hibernate的
原生XML格式完成,且并列使用JPA注解和XML描述符。我们还深入探讨细粒度领域模型的映射,以及如何映射
属性和嵌入的组件。
1细粒度的领域建模
Hibernate的一个主要目标是支持细粒度的领域建模,过去我们把它分离出来作为富领域模型最重要的必要条件。
这是我们使用POJO的一个原因,粗略的说,细粒度意味着类比表要多。
2映射带有同一性的实体
持久化使事情变得复杂起来。利用对象/关系持久化,持久化对象是数据库表的一个特定行的内存表示。连同Java同一性(内存位置)
和对象等同性一起,你还要选择数据库同一性(在持久化数据库仓库中的位置)。
1、如果对象在JVM中占据着相同的内存位置,他们就是同一的。这可以通过使用==操作符进行检查。这个概念称作对象同一性。
2、如果对象有着相同的值,他们就是相等的,如equals方法定义的一样。不显示覆盖这个方法的类,继承了由Object定义的实现,
他比较对象同一性。这个概念称作等同性。
3、如果存储在一个关系数据库中的对象标识相同的行,或者他们共享相同的表和主键值,他们就是同一的。这个概念称作数据库同一性。
试验证明在同一个EntityManager里面,同一个id的对象是 == 的,也是同一个对象。
通常声明setId()方法为私有,并让hibernate生成和设置标示符值。
生成器名称 JPA GenerationType 选项 描述
Native AUTO Native同一性生成器挑选其他同一性生成器如identity、sequence或者hilo,取决于底层数据库的能力。使用这个生成器保证映射元数据可以移植到不同的数据库管理器
Identity IDENTITY 这个生成器支持DB2、Mysql、MS SQL Server、Sybase和HypersonicSQL中的同一性列。返回的标示符类型为long、short或者int。
Sequence SEQUENCE Sequence、
Parameters 这个生成器在DB2、PostgreSQL、Oracle、SAPDB或者Mckoi中创建一个序列:或者使用InterBase中的一个生成器。返回的标示符类型为long、short或者int。如果创建序列的其他设置要被添加到DDL,就使用sequence选择给序列定义一个目标名称(默认是hibernate_sequence)和paramters
3类映射选项
Hibernate生成update语句,会更新所有的列。
在有些情况下,例如包含几百列的一个遗留表,在该表中,即使最简单的操作的sql语句也很大,必须关闭这个启动时
的sql生成,并切换到运行时生成的动态语句。当大量实体时,也会影响启动时间,因为hibernate必须为CURD提前生
成所有SQL语句:
区别就是:
Hibernate: insert into USER (user_Name) values (?)
Hibernate: insert into USER (user_Name, password) values (?, ?)
配置:
- <class name="User" table="USER" dynamic-insert="true" dynamic-update="true">
- @org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true)
使实体不可变:
一个特定类的实例可以是不可变的。
效果:
没有sql打印,也没有报错,也就是忽略了更新操作
配置:
- <class name="User" table="USER" dynamic-insert="true" dynamic-update="true"
- mutable="false">
- @org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true,mutable=false)
- @org.hibernate.annotations.AccessType
- The annotation @org.hibernate.annotations.AccessType should be considered deprecated for FIELD and PROPERTY access. It is still useful however if you need to use a custom access type.
用引号把SQL标示符括起来。
·实体数据库命名约定;
- package cn.partner4java.shop.bean;
- import org.hibernate.cfg.ImprovedNamingStrategy;
- /**
- * 使每个表前面加上"PA_"
- * @author partner4java
- *
- */
- public class PANamingStrategy extends ImprovedNamingStrategy {
- /**
- * 当没有声明显示的名称时调用
- */
- @Override
- public String classToTableName(String className) {
- return "PA_"+ super.classToTableName(className);
- }
- /**
- * 当声明了显示的名称时调用
- * Alter the table name given in the mapping document
- */
- @Override
- public String tableName(String tableName) {
- return "PA_"+ super.tableName(tableName);
- }
- }
- package cn.partner4java.shop.service;
- import org.hibernate.cfg.Configuration;
- import cn.partner4java.shop.bean.PANamingStrategy;
- public class BaseTest {
- public static void main(String[] args) {
- Configuration configuration = new Configuration();
- configuration.setNamingStrategy(new PANamingStrategy());
- configuration.configure().buildSessionFactory();
- }
- }
配置:<class name="BankAccount"> 生成表明:pa_bank_account
配置:<class name="BankAccount" table="BankAccount"> 生成表明:pa_bank_account (书中说的是错误的)
配置:<class name="BankAccount" table="BANK_ACCOUNT"> 生成表明:pa_bank_account
4细粒度的模型和映射
但是最少包括not-null属性,因为还没有提交给数据库之前会报告空指针异常。(看看save源码都做了些什么)
被注解的实体从强制的@Id注解的位置继承默认的访问策略。(如果@Id已经在字段中而不是获取方法上声明,
那么所有其他的属性 映射注解也必须在字段中)
@Transient
声明此字段不被 映射到数据库中
指定注解位置:
- @AccessType(value="field") //@AccessType(value="property")
- public class TestBean1 implements Serializable {
会报的错误:
Caused by: org.hibernate.AnnotationException: No identifier specified for entity: cn.partner4java.jpa.bean.TestBean1
关联属性:
一些字段可以不存在于表中,而是关联的一些属性,比如关联显示每个一个货物的所有出价平均值:
- @Formula("slect AVG(b.AMOUNT) from BID b where b.ITEM_ID = ID ")
- <property name="" formula="slect AVG(b.AMOUNT) from BID b where b.ITEM_ID = ID "></property>
那么这个字段也不会出现在插入和更改SQL中
前面我们说过可以使一个实体不可变(mutable="false"),那么也可以使一个字段不可变,忽略变动:
- @Column(updatable=false,insertable=false)
- <property name="" update="false" insert="false"></property>
在此基础上来实现:生成的默认属性:
就是有一些字段,比如是利用触发器生成的,也就是不是我们这里完成的,是第三方触发完成,那么当你插入或者更新完之后,又想获得的对象包括这个触发值,那么可以:
- @org.hibernate.annotations.Generated(GenerationTime.ALWAYS)//GenerationTime.INSERT等
- <property name="" update="false" insert="false" generated="always"></property>
默认值(有两点是必须注意的,一个是必须是null,一个是会引起为null):
- <property name="">
- <column name="" default="1"></column>
- </property>
- @Column(columnDefinition="INTEGER default '1'")
private Integer age;//*注意这里必须给Integer,因为int类型是有默认值0的 (也就是插入对象的这个属性的值必须是null)
(DLL: `age` int(11) default '1',)
*你还必须开启动态的插入更新语句的生成(@org.hibernate.annotations.Entity(dynamicInsert=true,dynamicUpdate=true),以便包括默认值的列不会出现在每个语句中,
否则将插入的是null。
映射组件:
- @Embedded
- private Address homeAddress;
- @Embeddable
- public class Address implements Serializable {
- private String street;
- private String city;
这两个字段就会包含到homeAddress属性的类里面。
xml:
- <component name="homeAddress" class="Address">
- <property name=""></property>
- </component>