*.hbm.xml文件 hbm解释:hibernate-mapping
映射文件说明
Hibernate-mapping
--类层次:class
主键:id
基本类型:property
实体引用类:many-to-one | one-to-many
集合:set | list | map | array
One-to-one
Many-to-many
子类:subclass|joined-subclass
其他component | any等
查询语句:query(用来放置查询语句,便于对数据库查询的统一管理和优化)
每个Hibernate-mapping中可以同时定义多个类,但更推荐为每个类都创建一个单独的映射文件
<hibernate-mapping package="com.clou.entity">
<class name="News" table="news" dynamic-update="true">
<id name="id">
<column name="id"></column>
<generator class="native"></generator>
</id>
<property name="title" type="string" />
<property name="author" type="string" />
<property name="date" type="date" />
</class>
</hibernate-mapping>
/**
* 如果没有在class标签中设置 dynamic-update属性设置为true时,
* 下面方法运行后会更新除了id的所有字段
* 如果设置后只会动态的更新修改过的字段值
* dynamic-insert 属性的设置和这个属性的原理是一样的
*/
@Test
public void testDynamicUpdate(){
News news = (News) session.get(News.class, 1);
news.setAuthor("ABCD");
}
映射对象标识符
Hibernate使用对象标识符(OID)来建立内存中对象和数据库表中记录的对应关系,对象的OID和数据库表的主键对应,Hibernate通过标示符生成器来为主键赋值。
Hibernate推荐在数据表中使用代理主键,即不具备业务含义的字段,代理主键通常为整数类型,因为整数类型比字符串类型要节省更多的数据库空间,
在对象-关系映射文件中,<id>元素用来设置对象标识符,<generator>子元素用来设定标识符生成器。
Hibernate提供了标识符生成器接口:IdentifierGenerator并提供了各种内置实现
<hibernate-mapping>是hibernate映射文件的跟元素
Default-cascade(默认为none)设置hibernate默认的级联风格,若配置Java属性集合映射时没有指定cascade属性,则Hibernate将采用此处指定的级联风格。
Default-access(默认为property):指定Hibernate的默认的属性访问策略。属性值为property,即使用getter,setter方法来访问属性,若指定access,则Hibernate会忽略getter/setter方法,而通过反射访问成员变量。
Default-lazy(默认为true):设置Hibernate moming的延迟加载策略,该属性值为true,即启用延迟加载策略,若配置Java属性映射,集合映射时没有指定lazy属性,则Hibernate将采用此处指定的延迟加载策略
Package(可选):指定一个包前缀,如果在映射文档中没有指定全限定的类名,就是用这个作为包名。
<class>标签 用于指定类和表的映射
Name属性:
Table属性:
Dynamic-insert若设置为true,标识当保存一个对象时,会动态生成insert语句,insert语句中仅包含所有取值不为Null的字段,默认为false.
dynamic-update:若设置为true,表示当更新一个对象时,会动态生成update语句,update语句中仅包含所有取值需要更新的字段,默认值为false.
Batch-size:指定根据OID来抓取实例时,每批抓取的实例数。
Lazy:指定是否延迟加载。
Mutable=”true”
select-before-update=”false”(默认) : 对游离对象采用两种方法,update和 saveOrUpdate(obj)方法有效果 ,先查后在决定是否更新。
<id>标签:设定持久化类的OID和表的主键的映射
name:标识持久化类OID的属性名
column:设置标识属性所映射的数据表的列名(主键组点的名字)
unsaved-value:若设置了该属性,Hibernate会通过比较持久化类的OID值和该属性值来区分当前持久化类的对象是否为临时对象。
type:指定Hibernate映射类型。Hibernate映射类型是Java类型与SQL类型的桥梁。如果没有为某个属性显示设定映射类型,Hibernate会运用反射机制先识别出持久化类的特定属性的Java类型,然后自动使用与之对应的默认的Hibernate映射类型。
Java的基本数据类型和包装类型对应相同的Hibernate映射类型。基本数据类型无法表达null,所以对于持久化类的OID推荐使用包装类型。
主键生成策略generator
Hibernate提供的内置标识符生成器:
Increment:适用于代理主键,由Hibernate自动以递增方式生成。
Identity:适用于代理主键,由底层数据库生成标识符。
Sequence:适用于代理主键,Hibernate根据底层数据库的序列生成标识符,这要求底层数据库支持序列
Hilo适用于代理主键,hibernate分局high/low算法生成标识符。
Seqhilo:适用于代理逐渐,使用一个高/低算法来搞笑的生成long,short或者int类型的标识符,
Native适用于代理主键,根据底层数据库对自动生成标识符的方式,自动选择identity,sequence 或者hilo
Uuid.hex:适用于代理主键,hibernate采用128位的UUID算法生成标识符。
Foreign:适用于代理主键,使用另外一个相关联的对象的标识符。
Increment标识符生成器
Increment标识符生成器由Hibernate以递增的方式为代理主键赋值:
Hinernate先会读取News表中的主键的最大值,而接下来向NEWS 表中插入记录时,就在max(id)的基础上递增,增量为1:所以有并发问题
适用范围:只适用于测试的时候
Identity标识符生成器
Identity标识符生成器,由底层数据库来负责生成标识符,它要求底层数据库把主键定义为自动增长字段类型
适用范围:由于identity生成标识符的机制依赖于底层数据库系统,因此,要求底层数据库系统必须支持自动增长字段类型,支持自动增长字段类型的数据库包括:DB2,Mysql,MSSQLServer,Sybase 等不能为Oracle类型
OID必须为long ,int 或short类型,如果把OID定义为byte类型,在运行时会抛出异常。
Sequence标识符生成器
Sequence标识符生成器利用底层数据库提供的序列来生成标识符。
<id name=”id”>
<generator class=”sequence”>
<param name=”sequence”>news_seq</param>
</generator>
</id>
Hilo标识符生成器
Hilo标识符生成器由Hibernate按照一种high/low算法* 生成标识符,它从数据库的特定表的字段中获取high值
<id name=”id”>
<generator class=”hilo”>
<param name=”table”>hi_table<param>
<param name=”column”>next_value</param>
<param name=”max_lo”>10</param>
<generator>
</id>
Hibernate在持久化一个News 对象时 ,由Hibernate负责生成主键值。Hilo标识符生成器在生成标识符时,需要读取并修改hi_table表中的next_value值
适用范围:
由于hilo标识符机制不依赖于底层数据库系统,因此它适合所有的数据库系统
OID必须为long, int 或short类型,如果把OID定义为byte类型 ,插入时会抛出异常。
Native标识符生成器
Native标识符生成器依据底层数据库对自动生成标识符的支持能力,来选择使用identity , sequence 或 hilo标识符生成器。
适用范围:
适用于跨市平台开发
OID必须为long, int , short 类型, 如果为byte类型 运行时会抛出异常
<property>节点
property 元素用于指定类的属性和表字段的映射
name:指定该持久化类的属性的名字。
column:指定与类的属性映射的表的字段名,如果没有设置该属性,Hibernate将直接使用类的属性名作为字段名。
type:指定Hibernate映射类型。Hibernate映射类型是Java类型与SQL类型的桥梁。如果没有为某个属性显示设定映射类型,Hibernate会运用反射机制先识别出持久化类的特定属性的Java类型,然后自动使用与之对应的默认的Hibernate映射类型。
Java的基本数据类型和包装类型对应相同的Hibernate映射类型。基本数据类型无法表达null,所以对于持久化类的OID推荐使用包装类型。
Not-null: 若该属性值为true, 表明不允许null,默认为false;
Access:指定Hibernate的默认的属性访问策略、默认为property,即使用getter , setter方法来访问属性,若指定field,则Hibernate会忽略getter/setter方法,而通过反射访问成员变量。
Unique : 设置是否为该属性所映射的数据列添加唯一约束。
Update : 默认为true标识该字段的值可以被修改,如果该属性的值为false时,标识该字段的值不能被修改 ,若修改该字段的值 ,也不会报错,但在数据库中得不到修改后的值(property标签中的update属性)
Index : 指定一个字符串的索引名称,当系统需要Hibernate自动创建表时,用于为该属性所映射的数据列创建索引,进而加快该数据列的查询。
Length:
formula: 设置一个SQL表达式,Hibernate将根据它来计算出派生属性的值。
派生属性:并不是持久化类的所有属性都直接和表的字段匹配,持久化类的有些属性的值必须在运行时通过计算才能得出来,这些属性称为派生属性。
使用formula属性时,
formula=”(sql)”的英文括号不能少。
sql表达式中的列名和表名都应该和数据库对应,而不是和持久化对象的属性对应
如果需要在formula属性中使用参数,这直接使用where cur.id = id 形式,其中id就是参数,和当前持久化对象的id属性对应的列的id值将作为参数传入。
public class News {
private Integer id;
private String title;
private String author;
private Date date;
//该属性值为: title:author
private String desc;
<hibernate-mapping package="com.clou.entity" >
<class name="News" table="news" dynamic-update="true">//动态更新,只根据已有的字段生成更新语句
<id name="id">
<column name="id"></column>
<generator class="native"></generator>
</id>
<property name="title" type="string" />
<property name="author" type="string" />
<property name="date" type="date" />
<!-- 映射派生属性 -->
<property name="desc" formula="(select concat(author,':',title) from news n where n.id = id)">
</property>
</class>
</hibernate-mapping>
映射Java的时间日期类型:
1) 两个基础知识:
I 在Java中,代表时间和日期的类型包括:java.util.Date和java.util.Calendar
此外,在JDBC API中还提供了3个扩展了java.util.Date类的子类:java.sql.Date
Java.sql.Time 和java.sql.Timestamp , 这三个类分别和标准SQL类型中的
DATE , TIME , 和 TIMESTAMP类型对应
II,在标准SQL中,DATE 类型表示日期,TIME 类型表示时间,TIMESTAMP类型表示时间戳,同时包含日期和时间信息
2) 如何进行映射?
因为java.util.Date是java.sql.Date,Java.sql.Time 和java.sql.Timestamp 类的父类 ,所以java.util.Date可以对应标准SQL类型中的DATE , TIME , 和TIMESTAMP
基于I,所以在设置持久化类的Date类型时,设置为java.util.Date. 因为java.util.Date可以映射java.sql中的任何日期类型
如何把java.util.Date映射为DATE , TIME , 和TIMESTAMP ?
可以通过property的type属性类进行映射:
例如
<property name=”date” type=”date”>
<column name=”DATE”/>
</property>
<property name=”date” type=”time”>
<column name=”DATE”/>
</property>
<property name=”date” type=”timestamp”>
<column name=”DATE”/>
</property>
其中timestamp , date , time 即不是Java类型,也不是标准SQL类型,而是hibernate映射类型。
以下情况下必须显示指定Hibernate映射类型
一个Java类型可能对应多个Hibernate映射类型,例如:如果持久化类的属性为java.util.Date类型,对应的Hibernate映射类型可以是date , time , 或timestamp。
此时必须根据对应的数据表的字段的SQL类型,来确定Hibernate映射类型,如果字段为DATE类型,那么hibernate映射类型为date, 如果字段为TIME类型,那么Hibernate映射类型为time,如果字段为TIMESTAMP类型,那么Hibernate映射类型为timestamp。
Java大对象类型的Hibernate映射
在Java中,java.lang.String 可用于表示长字符串(长度超过255),字节数组byte[] 可用于存放图片或文件的二进制数据。此外,在JDBC API中海提供了 java.sql.Clob和java.sql.Bolb类型,它们分别和标准SQL中的CLOB 和BOLB类型对应,CLOB表示字符串大对象(Character Large Object), BLOB表示二进制对象(Binary Large Object)
映射类型 binary text clob blob
Java类型 byte[] java.lang.String java.sql.Clob java.sql.Blob
标准SQL类型 varchar(或BLOB)CLOB CLOB BLOB
MYSQL类型 BLOB CLOB CLOB BLOB
Oracle类型 BLOB CLOB CLOB BLOB
Mysql不支持标准SQL的CLOB类型,在Mysql中,用TEXT , MEDIUMTEXT及LONGTEXT类型来表示长度操作255的长文本数据
在持久化类中,二进制大对象可以声明为byte[]或java.sql.Blob类型;字符串可以声明为java.lang.String 或jva.sql.Clob
实际上在Java应用程序中处理长度超过255的字符串,使用java.lang.String比java.sql.Clob更
public class News {
private Integer id;
private String title;
private String author;
private Date date;
//该属性值为: title:author
private String desc;
//大文本类型
private String content;
//二进制数据
private Blob image;
<class name="News" table="news" dynamic-update="true">
<id name="id">
<column name="id"></column>
<generator class="native"></generator>
</id>
<property name="title" type="string" />
<property name="author" type="string" />
<property name="date" type="date" />
<!-- 映射派生属性 -->
<property name="desc" formula="(select concat(author,':',title) from news n where n.id = id)">
</property>
<!-- 映射大对象-->
<!-- <property name="content" type="clob"></property> -->
<!--
如果使用这种方式生成数据库的表 该字段的type类型是longtext类型如果想
若希望精确映射SQL 类型, 可以使用 sql-type属性
-->
<property name="content" >
<column name="CONTENT" sql-type="mediumtext"></column>
</property>
<!-- <property name="image" type="blob"></property>-->
<property name="image">
<column name="IMAGE" sql-type="mediumblob" />
</property>
</class>
@Test
public void testBlob() throws IOException, SQLException{
News news = new News();
news.setAuthor("cc");
news.setContent("CONTENT");
news.setDate(new Date());
news.setDesc("DESC");
news.setTitle("CC");
//该图片存放在项目下,得到一个输入流把它写出去
InputStream stream = new FileInputStream("Hydrangeas.jpg");
//保存时需要借助Hibernate的getLobCreator() 的createBlob方法
Blob image = Hibernate.getLobCreator(session)
.createBlob(stream, stream.available());
news.setImage(image);
session.save(news);
InputStream in = image.getBinaryStream();
System.out.println(in.available());//得到的是文件的大小
}
@Test
public void testhuoquBlob(){
//上面测试的是保存,这个方法测试获取Blob对象
News news = (News) session.get(News.class, 1);
Blob image = news.getImage();
}
通常是把文件传到一个指定文件夹下,然后在数据表中设置一个path(dir)字段,这个字段指向那个文件
映射组成关系,
建立域模型和关系数据模型有着不同的出发点
域模型:由程序代码组成,通过细化持久化类的粒度,可提高代码的可重用性,简化编程。
关系数据模型:在没有冗余的情况下,应该尽可能减少表的数目,简化表之间的参照关系,以便提高数据数据的访问速度。
因此,有时候我们看到两个Java类中对应的却是一张数据库表
Hibernate把持久化类的属性分为两种:
值(value)类型:没有OID,不能被单独持久化,生命周期依赖于所属的持久化类的对象的生命周期。
实体(entity)类型:有OID,可以被单独持久化,有独立的生命周期。
显然无法直接用property映射pay属性
Hibernate使用<component>元素来映射组成关系,该元素表名pay属性时Worker类的一个组成部分,在Hibernate中称之为组件
<component>元素来映射组成关系
Class:设定组成关系属性的类型,此处表明pay属性为pay类型
<paremt>元素指定组件属性所属的整体类
Name:整体类在组件类中的属性名
例如:
public class Worker {
private Integer id;
private String name;
private Pay pay;
public class Pay {
private int monthlyPay;
private int yearPay;
private int vocationWithPay;
<hibernate-mapping package="com.clou.entity" >
<class name="Worker" table="worker" >
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="native"></generator>
</id>
<property name="name" type="string">
<column name="name"></column>
</property>
<!-- 映射组成关系使用component -->
<component name="pay" class="Pay"><!-- 因为package属性已经设置了 -->
<!-- 指定组成关系的组件的属性 -->
<property name="monthlyPay" column="monthly_pay"></property>
<property name="yearPay" column="year_pay"></property>
<property name="vocationWithPay" column="vocation_with_pay"></property>
</component>
</class>
</hibernate-mapping>
测试方法:
@Test
public void testComponent(){
Worker worker = new Worker();
Pay pay = new Pay();
pay.setMonthlyPay(1000);
pay.setYearPay(80000);
pay.setVocationWithPay(5);
worker.setName("ABCD");
worker.setPay(pay);
session.save(worker);
}
测试2:
例如:
public class Worker {
private Integer id;
private String name;
private Pay pay;
public class Pay {
private Worker worker;
private int monthlyPay;
private int yearPay;
private int vocationWithPay;
<hibernate-mapping package="com.clou.entity" >
<class name="Worker" table="worker" >
<id name="id" type="java.lang.Integer">
<column name="id"></column>
<generator class="native"></generator>
</id>
<property name="name" type="string">
<column name="name"></column>
</property>
<!-- 映射组成关系使用component -->
<component name="pay" class="Pay"><!-- 因为package属性已经设置了 -->
<parent name=”worker”/><!—这样效果跟上面是一样的 ,只是更进一步的指定了关系-->
<!-- 指定组成关系的组件的属性 -->
<property name="monthlyPay" column="monthly_pay"></property>
<property name="yearPay" column="year_pay"></property>
<property name="vocationWithPay" column="vocation_with_pay"></property>
</component>
</class>
</hibernate-mapping>
测试方法:
@Test
public void testComponent(){
Worker worker = new Worker();
Pay pay = new Pay();
pay.setMonthlyPay(1000);
pay.setYearPay(80000);
pay.setVocationWithPay(5);
worker.setName("ABCD");
worker.setPay(pay);
session.save(worker);
}