Hibernate的映射文件
映射文件的结构和属性
一个映射文件(mapping file)由一个根节点<hibernate-mapping>和多个<class>节点组成,
首先看看根节点<hibernate-mapping>支持什么属性:
<hibernate-mapping
schema="schemaName" (1)
catalog="catalogName" (2)
default-cascade="cascade_style" (3)
default-access="field|property|ClassName" (4)
default-lazy="true|false" (5)
auto-import="true|false" (6)
package="package.name" (7)
/>
这8个属性都是可选的,下面解释几个重要的属性,
default-lazy:延迟加载,默认为true,Hibernate通过默认加载提升性能,通常建议设置为true。在后面的配置属性和集合映射时也可以指定lazy值
auto-import:是否允许查询语句中使用非全限定类名,默认为true,当一个映射文件中有两个持久化类,包名不同,类名相同时,需要设置auto-import为false才能区分。
package:设置该值之后,映射文件就不再需要指定全限定类名
再看看<class>标签支持什么样的属性,
<class
name="ClassName" (1)
table="tableName" (2)
discriminator-value="discriminator_value" (3)
mutable="true|false" (4)
schema="owner" (5)
catalog="catalog" (6)
proxy="ProxyInterface" (7)
dynamic-update="true|false" (8)
dynamic-insert="true|false" (9)
select-before-update="true|false" (10)
polymorphism="implicit|explicit" (11)
where="arbitrary sql where condition" (12)
persister="PersisterClass" (13)
batch-size="N" (14)
optimistic-lock="none|version|dirty|all" (15)
lazy="true|false" (16)
entity-name="EntityName" (17)
check="arbitrary sql check condition" (18)
rowxml:id="rowid" (19)
subselect="SQL expression" (20)
abstract="true|false" (21)
node="element-name"
/>
一对<class>就代表一个持久化实体类,即数据库中的表,在<class>元素下,通常还会有<id>和<property>子元素,用来构成表的各个字段,<id>通常用来映射主键,<property>则用来映射普通字段,另外还可以通过<set> <map>等映射集合字段,下面一一讲解。
映射主键(<id...>
Hibernate建议为持久化类定义一个标识属性(identifier property),如private int id, 标识属性映射数据库底层的主键字段(primary key column )。在映射文件中,标识属性用<id>表示,<id>标签支持以下属性:
<id
name="propertyName" (1)
type="typename" (2)
column="column_name" (3)
unsaved-value="null|any|none|undefined|id_value" (4)
access="field|property|ClassName"> (5)
node="element-name|@attribute-name|element/@attribute|." <generator class="generatorClass"/>
</id>
unsaved-value:指定刚创建尚未保存时的标识属性值,用来区分已经加载到session但未再次持久化的实例,Hibernate 3中已经不需要指定这个属性。
上面几个属性通常只需要指定 name, type, column这三个属性,在泛型中,type属性也不需要指定,Hibernate会通过反射获取字段类型
在Hibernate中,提供了一个逻辑主键生成器,在映射文件中通过<id>元素的子元素<generator>表示,可以为每个持久化类生成唯一逻辑主键,
主键生成器<generator>的class属性支持以下值,代表不同种类的主键生成器策略,
<generator class="increment|identity|sequence|hilo|seqhilo|uuid|guid|native|assigned|select|foreign" />
其中最常用的identiry,适合DB2,MySQL, MSSQL等支持自增长字段的数据库,可以返回long, short, int等。
sequence,适合DB2,Oracle等。
映射普通属性(<property...>
<property>标签支持以下属性,
<property
name="propertyName" (1)
column="column_name" (2)
type="typename" (3)
update="true|false" (4)
insert="true|false" (4)
formula="arbitrary SQL expression" (5)
access="field|property|ClassName" (6)
lazy="true|false" (7)
unique="true|false" (8)
not-null="true|false" (9)
optimistic-lock="true|false" (10)
generated="never|insert|always" (11)
node="element-name|@attribute-name|element/@attribute|."
index="index_name"
unique_key="unique_key_id"
length="L"
precision="P"
scale="S"
/>
通常情况下只需指定name, column, type的值, 另外部分属性解释如下
update和insert:输入属性值不需要Hibernate生成,则指定为false
formula=(sql):直接写SQL获取数据,括号不能少
lazy:是否延迟加载,默认为false
下面演示一下formula的用法,
如果我们在实体类Person.java中有一个普通属性 private String fullContent;
private String fullContent;
在映射文件中,这个属性的值是通过formula的方式获取的,则映射文件应该这么写,
...
<property name="fullContent" formula="(select concat(p.name,p.age) from person_inf p where p.person_id = person_id)" />
...
这样,我们在测试类中如果要获取这个属性值的话,就会取formula的值
Person p = (Person)sess.get(Person.class, 3);
System.out.println(p.getFullContent());
上面的例子只是得到一个实体类的属性字段值,但是在数据库层面并没有生成这个字段,
要想数据库也生成这个字段,则要通过<property>标签的generated属性来指定, 例如
...
<property name="fullContent" column="full_content" type="string" generated="insert" />
...
同时,需要有一个数据库的触发器配合使用才能实现上面的功能,
drop database test;
create database test;
use test;
create table person_inf
(
id auto_increment primary key,
title varchar(255) not null,
content varchar(255)
full_content varchar(255)
);
DELEMITER |
create trigger t_full_content_gen BEFORE INSERT ON person_inf
FOR EACH ROW BEGIN
set person_inf.full_content=concat(person_inf.title, person_inf.content);
END;
|
DELIMITER ;
先执行上面的SQL脚本,然后才执行java程序,另外需要将hibernate.cfg.xml的hbm2ddl.auto改为update,避免重建数据库时丢失触发器。
之后,便可以像上面那样访问这个属性了,
1 Person p = (Person)sess.get(Person.class, 3);
2 System.out.println(p.getFullContent());
映射集合属性
在一个实体类中,有标志属性,普通属性,经常还会有集合属性,集合属性中会包含多个值,多个值与实体类形成一对多的关联关系。
例如Set集合,List集合,Map集合等等,比如下面这样的实体类定义,
public class SetPerson {
private int id;
private String name;
private int age;
private Set<String> schools = new HashSet<String>();
...
这里的schools就是一个集合属性。
Hibernate要求集合属性必须声明为接口而不是实现类,可以是java.util.Set, java.util.List, java.util.Map等。
集合属性将会保存在单独的表中,当实体类对象保存时,集合属性也会自动持久化(即保存到单独表中去),当实体类对象删除时,集合属性也会自动删除;当集合从一个实体类对象传递到另一个持久化对象时,集合记录也会从一个表转移到另一个表。
-集合标签
常用的集合属性在映射文件中的元素有 <list>, <set>, <map>, <array>, <bag>,<idbag>, <rimitive-array>等,这些集合属性元素标签也有自己的属性,部分属性解释如下:
table:表名(集合属性元素需要单独存在一张表里)
lazy:默认为true,延迟加载
inverse:反转集合属性与实体类关联的控制权,这个对于Set之类的无序集合在性能提升上有用
sort:有序集合排序属性
order-by:也是指定排序,不过是通过SQL语句实现
-外键
由于集合元素和实体类是一个从属关系,所以在集合元素中需要有一个外键,与实体类的标志属性相关联。这个外键在映射文件中通常用<key>标签标识,<key>标签也有自己的属性,如column, on-delete, property-ref,update,unique等等。
-索引
对于有序集合,都需要指定一个索引列,无序集合(Set,bag)则不需要。例如在
<list-index>,List或者数组集合中用来表示索引,
<map-key>,映射Map集合,基本数据列的索引
<map-key-many-to-many>, 映射Map集合,实体引用类索引
<composite-map-key>, 映射Map集合,复合数据类型的索引
-数据列
在映射文件中的集合元素,通常还会有一个数据列,根据不同的数据类型,在映射文件中的标签可能不同,通常会有以下几种
<element> 基本数据类型,或者其包装类型
<composite-element>复合类型
<one-to-many>或<many-to-many>引用类型
下面,将针对List, Set, Map, SortedMap等不同的集合属性具体说明每种集合属性的特性
List集合属性
List是有序集合, 因此需要一个索引列来表示集合的次序。 下面演示List集合属性的用法,
首先定义一个持久化实体类ListPerson, 类中定义了一个List集合属性 schools.
package hib; import java.util.ArrayList;
import java.util.List; public class ListPerson {
private int id;
private String name;
private int age;
private List<String> schools = new ArrayList<String>(); public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public List<String> getSchools() {
return this.schools;
}
public void setSchools(List<String> schools) {
this.schools = schools;
} }
对于这个持久化类, 其映射文件如下, 在映射文件中,我们定义了外键标签<key>用来关联集合属性和持久化类,
定义了索引列<list-index>来记录集合属性元素的次序,定义了数据列<element>来保存集合元素的值
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="hib">
<class name="ListPerson" table="Person_inf">
<id name="id" column="person_id" type="int">
<generator class="identity" />
</id>
<property name="name" type="string" />
<property name="age" type="int" />
<list name="schools" table="school">
<!-- 外键列-->
<key column="personid" not-null="true"/>
<!-- 索引列 -->
<list-index column="list_order"/>
<!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
<element type="string" column="school_name" />
</list>
</class>
</hibernate-mapping>
下面写一个测试类用来测试上面的持久化类,
package hib; import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet; import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport; public class PersonManager {
private static void exec(String resource, Object obj) {
// 打开线程安全的session
Configuration conf = new Configuration().configure();
conf.addResource("hib/"+resource);
// 用Configuration创建SessionFactory
SessionFactory sf = conf.buildSessionFactory();
// 用SessionFactory打开Session
Session sess = sf.openSession();
Transaction tx = sess.beginTransaction();
sess.save(obj);
tx.commit();
sess.close();
sf.close();
}
private static void listTest() {
ListPerson lp = new ListPerson();
lp.setAge(20);
lp.setName("xiao ming");
List<String> schools = new ArrayList<String>();
schools.add("小学");
schools.add("中学");
lp.setSchools(schools);
exec("ListPerson.hbm.xml", lp);
} public static void main(String[] args) {
listTest();
}
}
PersonManager类中定义了一个通用方法private static void exec(String resource, Object obj)用来保存持久化类实例,
在方法listTest()中,实例化了一个持久化类ListPerson, 并且实例化了一个集合属性schools并赋值。
运行PersonManager.java之后,发现数据库中多了两张表,person_inf和school,且两张表通过personid关联(即在school表中增加了外键约束如下:FK_48amgp8tko414xxqs1q1vaat4)。
eclipse中执行结果,
Hibernate: drop table if exists Person_inf
Hibernate: drop table if exists school
Hibernate: create table Person_inf (person_id integer not null auto_increment, name varchar(255), age integer, primary key (person_id))
Hibernate: create table school (personid integer not null, school_name varchar(255), list_order integer not null, primary key (personid, list_order))
Hibernate: alter table school add constraint FK_48amgp8tko414xxqs1q1vaat4 foreign key (personid) references Person_inf (person_id)
十二月 29, 2016 11:11:30 下午 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: insert into Person_inf (name, age) values (?, ?)
Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
mysql中的数据,
总共有两张表
MariaDB [information_schema]>
MariaDB [information_schema]> select table_name from tables where table_schema =
'test';
+------------+
| table_name |
+------------+
| person_inf |
| school |
+------------+
2 rows in set (0.00 sec)
实体类表
MariaDB [(none)]> use test;
Database changed
MariaDB [test]>
MariaDB [test]> select * from person_inf;
+-----------+-----------+------+
| person_id | name | age |
+-----------+-----------+------+
| 1 | xiao ming | 20 |
+-----------+-----------+------+
1 row in set (0.00 sec)
MariaDB [test]>
集合属性表
MariaDB [test]> select * from school;
+----------+-------------+------------+
| personid | school_name | list_order |
+----------+-------------+------------+
| 1 | 小学 | 0 |
| 1 | 中学 | 1 |
+----------+-------------+------------+
2 rows in set (0.00 sec)
数组集合属性
Hibernate对数组和List的处理非常相似,只是前者长度不可变,后者可变而已,也因此数组集合一般是无法实现延迟加载的(长度不可变)。
将上面的list集合修改成数组集合,代码如下,
持久化类,
package hib; import java.util.ArrayList;
import java.util.List; public class ArrayPerson {
private int id;
private String name;
private int age; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public String[] getSchools() {
return schools;
}
public void setSchools(String[] schools) {
this.schools = schools;
} private String[] schools;
}
映射文件,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="hib">
<class name="ArrayPerson" table="Person_inf">
<id name="id" column="person_id" type="int">
<generator class="identity" />
</id>
<property name="name" type="string" />
<property name="age" type="int" />
<array name="schools" table="school">
<!-- 外键列-->
<key column="personid" not-null="true"/>
<!-- 索引列 -->
<list-index column="list_order"/>
<!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
<element type="string" column="school_name" />
</array>
</class>
</hibernate-mapping>
在测试类PersonManager.java中,新家一个测试方法arrayTest(),
private static void arrayTest() {
ArrayPerson ap = new ArrayPerson();
ap.setAge(20);
ap.setName("xiao ming");
String[] schools = new String[] {"小学","中学","大学"};
ap.setSchools(schools);
exec("ArrayPerson.hbm.xml", ap);
}
执行PersonManager.java, 看到hibernate生成的sql如下,
...
Hibernate: insert into person_inf (name, age) values (?, ?)
Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
Hibernate: insert into school (personid, list_order, school_name) values (?, ?, ?)
mysql中的数据,
person_inf表,
school表,
Set集合属性
Set集合与List集合不同,Set是无序集合,因此映射文件中就没有像list那样的索引列<list-index>。作为一个与持久化实例管理的集合属性,Set集合也是需要一个<key>外键来关联的,Set集合演示如下,
持久化类,
package hib; import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set; public class SetPerson {
private int id;
private String name;
private int age; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public Set<String> getSchools() {
return this.schools;
}
public void setSchools(Set<String> schools) {
this.schools = schools;
}
private Set<String> schools = new HashSet<String>();
}
映射文件,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="hib">
<class name="SetPerson" table="Person_inf">
<id name="id" column="person_id" type="int">
<generator class="identity" />
</id>
<property name="name" type="string" />
<property name="age" type="int" />
<set name="schools" table="school">
<!-- 外键列-->
<key column="personid" not-null="true"/>
<!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
<element type="string" column="school_name" not-null="true" />
</set>
</class>
</hibernate-mapping>
在PersonManager.java中新增一个测试方法setTest(),
private static void setTest() {
SetPerson sp = new SetPerson();
sp.setAge(20);
sp.setName("xiao ming");
Set<String> schools = new HashSet<String>();
schools.add("小学");
schools.add("中学");
sp.setSchools(schools);
exec("SetPerson.hbm.xml", sp);
}
运行PersonManager.java,查看mysql,能得到前面类似的结果
bag集合元素映射
<bag>可以映射list,映射Set,甚至映射Collection,但是不论映射成哪种集合,<bag>都会将它们映射为无序集合。
<bag>集合对应的表没有主键,在映射文件中通过<key>与持久化类关联,用<element>保存元素值,下面演示<bag>集合映射成Collection集合属性,
持久化类,
package hib; import java.util.ArrayList;
import java.util.Collection;
import java.util.List; public class BagPerson {
private int id;
private String name;
private int age; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public Collection<String> getSchools() {
return schools;
}
public void setSchools(Collection<String> schools) {
this.schools = schools;
} private Collection<String> schools = new ArrayList<String>();
}
映射文件, 注意在无序集合中<bag>标签中,可以添加一个order-by属性,直接以SQL实现,这个排序将会添加进hibernate生成的SQL中,通过数据库来实现排序,而不是在程序运行内存中排序。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="hib">
<class name="BagPerson" table="Person_inf">
<id name="id" column="person_id" type="int">
<generator class="identity" />
</id>
<property name="name" type="string" />
<property name="age" type="int" />
<bag name="schools" table="school" order-by="school_name asc">
<!-- 外键列-->
<key column="personid" not-null="true"/>
<!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
<element type="string" column="school_name" not-null="true"/>
</bag>
</class>
</hibernate-mapping>
在PersonManager.java中,添加一个新的测试方法bagTest(),
private static void bagTest() {
BagPerson sp = new BagPerson();
sp.setAge(20);
sp.setName("xiao ming");
Set<String> schools = new HashSet<String>();
schools.add("小学");
schools.add("中学");
sp.setSchools(schools);
exec("BagPerson.hbm.xml", sp);
}
执行PersonManager.java后会发现school表中只有两列,外键列和数据列,没有索引列,因为<bag>是无序集合,
Map集合属性
Map集合属性使用<map>标签,需要使用<key>列作为外键列和持久化类关联。Map是有序集合,因此还需要<may-key>类作为Map集合的索引。Map集合对应的表将以外键列和索引列作为联合主键。下面演示Map集合用法,
package hib; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map; public class MapPerson {
private int id;
private String name;
private int age; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public Map<String, Float> getScores() {
return scores;
}
public void setScores(Map<String, Float> scores) {
this.scores = scores;
} private Map<String, Float> scores = new HashMap<String, Float>();
}
映射文件,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="hib">
<class name="MapPerson" table="Person_inf">
<id name="id" column="person_id" type="int">
<generator class="identity" />
</id>
<property name="name" type="string" />
<property name="age" type="int" />
<map name="scores" table="score">
<!-- 外键列-->
<key column="person_id" not-null="true"/>
<!-- 索引列 -->
<map-key column="subject" type="string"/>
<!-- 数据列,这里的type属性其实可以省略,因为在实体类中使用了泛型,Hibernate会通过反射取得元素数据类型-->
<element column="grade" type="float" />
</map>
</class>
</hibernate-mapping>
在PersonManager.java中新增一个测试方法mapTest(),
private static void mapTest() {
MapPerson mp = new MapPerson();
mp.setAge(20);
mp.setName("xiao ming");
Map<String, Float> scores = new HashMap<String, Float>();
scores.put("语文", new Float(100.01));
scores.put("数学", new Float(130.05));
mp.setScores(scores);
exec("MapPerson.hbm.xml", mp);
}
执行PersonManager.java, mysql中score表的数据如下,subject将作为map集合索引, person_id + subject 将作为表的联合主键。
SortedSet和SortedMap集合映射
使用这两个集合作为集合实现类时,需要为<set>或者<map>标签指定sort属性,sort支持unsorted, natural, 以及通过java.utilComparator自定义排序。
下面演示一个SortedSet的用法,
持久化类,
package hib; import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet; public class SortedPerson {
private int id;
private String name;
private int age; public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
} public SortedSet<String> getTrainings() {
return trainings;
}
public void setTrainings(SortedSet<String> trainings) {
this.trainings = trainings;
} private SortedSet<String> trainings = new TreeSet<String>();
}
映射文件, 需要在<set>上添加sort属性,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="hib">
<class name="SortedPerson" table="person_inf">
<id name="id" column="person_id" type="int">
<generator class="identity" />
</id>
<property name="name" type="string" />
<property name="age" type="int" />
<set name="trainings" table="training" sort="natural">
<!-- 外键列-->
<key column="person_id" not-null="true"/>
<!-- 数据列 -->
<element column="training_name" type="string" not-null="true"/>
</set>
</class>
</hibernate-mapping>
在PersonManager.java中添加测试方法sortedSetTest(),
private static void sortedSetTest() {
SortedPerson ssp = new SortedPerson();
ssp.setAge(20);
ssp.setName("xiao ming");
SortedSet<String> trainings = new TreeSet<String>();
trainings.add("Wild Java Camp");
trainings.add("Sun SCJP");
ssp.setTrainings(trainings);
exec("SortedPerson.hbm.xml", ssp);
}
执行PersonManager.java,发现mysql中training表记录已经按照element列按字母排序,
数据库SQL排序
上面这种排序是在程序运行内存中实现的,之后再将已排序记录持久化到数据库中。
如果我们不希望用程序内心来排序,而是希望通过数据来排序,则可以在<set> <map> <bag>中添加order-by属性。
这种方式是通过继承LinkedHashSet或者LinkedHashMap来实现的,因此确保你的JDK版本至少大于1.4
例如我们可以在上面的SetPerson.hbm.xml中,在<set>标签中添加order-by属性,
<set name="schools" table="school" order-by="school_name asc">
集合属性的性能分析
延迟加载
Hibernate对集合属性默认采用延迟加载策略,即lazy="true". 因为集合属性很可能有成千上万条数据,而持久化类在实例化的时候并不一定会马上用关联的集合属性。
修改属性(增删改)的性能
集合可分两类
有序集合:集合元素可根据key或者index访问
无序集合:集合元素只能遍历
对于有序集合,因为有联合主键存在(主键已被索引),因此可以直接定位到相应元素进行修改,效率高。
对于无序集合,只有外键,没有索引,也就没有联合主键,也就没法按主键索引定位元素(可能可以建立索引,但性能可能非常差),修改这种集合性能将会很低。
因此对于<bag>这种集合,即没有索引字段,同时还不允许元素重复,hibernate无法直接判断元素是否重复,当需要修改集合属性值时,只能先删除全部集合,再重新创建集合,因此性能是最差的。
所以,对于有序集合属性的增,删,改将会有比较好的性能。(数组也是有序集合,但数组属性不支持延迟加载(因为长度固定),所以数组属性性能其实很低的)
延迟更新
对于多对多关联,值数据而言,如果改变Set集合的某个元素,hibernate并不能立即更新该元素对应的数据行。对于Set而言,只有在插入和删除操作时改变才有效。
反向集合(inverse="true")
修改Set集合属性性能并不高,但Hibernate还是处处采用了Set集合,这一方面是因为Set更贴近集合语意,
另一方面,在1-N关联中,1的一端通常都带有inverse="true"属性,即这种关联关系不再由一的一端维护,更新操作将在N的一端处理,这种情况下,无序考虑集合性能。
映射数据库对象
最后,还要来看看映射文件映射数据库对象,数据库对象指的是触发器,存储过程等等。Hibernate中使用<database-object>标签来映射数据库对象,用<create><drop>等标签标识具体的数据库操作,
下面演示映射创建数据表(DDL语句),
首先要定义一个映射文件,映射文件中可以用<create><drop>等指定具体的操作,然后直接将sql语句写在标签中。还可以添加一些<dialect>之类的标签指定更多属性,例如只在MySQL中有效,
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping>
<database-object>
<create>create table test(t_name varchar(255));</create>
<drop></drop>
</database-object>
</hibernate-mapping>
此映射文件不需要持久化类,我们直接在测试类中初始化一个Configuration对象并加载配置文件,打开一个SessionFactory,此映射文件就会生效,
在PersonManager.java中,新增测试方法dbObject()
private static void dbObject() {
//加载数据触发器来创建表
Configuration conf = new Configuration().configure();
conf.addResource("hib/DbObject.hbm.xml");
SessionFactory sf = conf.buildSessionFactory();
}
注意,通过这种方式创建表,好一定要将hibernate.cfg.xml中的hbm2ddl.auto设置为create才能生效
<property name="hbm2ddl.auto">create</property>
执行PersonManager.java将会创建一张test表,
除了上面根据配置文件生成表的方法之外,还可以使用hibernate自带工具SchemaExport(可直接命令行执行), 使用工具的代码如下,
映射文件保持不变,在PersonManager.java中,将dbObject()方法修改为,
private static void dbObject() {
//加载数据触发器来创建表
Configuration conf = new Configuration().configure();
conf.addResource("hib/DbObject.hbm.xml");
//SessionFactory sf = conf.buildSessionFactory(); SchemaExport se = new SchemaExport(conf);
se.setFormat(true).setOutputFile("new.sql").create(true, true); }
注意如果通过SchemaExport的方式创建表,hibernate.cfg.xml中的hbm2ddl.auto就不需要强制设置为create了,update也行。
执行PersonManger.java,也能创建test表。
Hibernate的映射文件的更多相关文章
- Hibernate之深入Hibernate的映射文件
这周周末 要把hibernate的映射文件搞定 .. 1.映射文件的主结构 主要结构 :根元素为<hibernate-mapping ></hibernate-mapping> ...
- 使用oracle数据库和MySQL数据库时hibernate的映射文件.hbm.xml的不同
假设是使用oracle数据库.那么hibernate的映射文件.hbm.xml例如以下: <id name="xuehao" column="xuehao" ...
- Hibernate的映射文件配置
对象关系的映射是用一个XML文档来说明的.映射文档可以使用工具来生成,如XDoclet,Middlegen和AndroMDA等.下面从一个映射的例子开始讲解映射元素,映射文件的代码如下: <?x ...
- 利用MyEclipse的ant插件生成Hibernate的映射文件
先下载:xdoclet-plugins-dist-1.0.4-bin build.xml文件 <?xml version="1.0" encoding="UTF-8 ...
- 使用 hibernate 根据映射文件生成数据库表
为了更好的显示效果,可以在hibernate.cfg.xml配置文件的<session-factory>标签里加入以下内容: 显示sql语句和格式化显示sql语句: <propert ...
- Hibernate的映射文件中基于主键的双向1对1的关联
1.Hibernate中采用基于主键的映射策略是,有一端(任意一端)的主键生成策略要是foreign,根据对方的主键来生成自己的主键,它的实体不能拥有自己的主键生成策略,如我的配置文件: <?x ...
- hibernate之映射文件VS映射注解
前言 对于java开发者而言,注解应该不是一个陌生的概念,早在JavaSE阶段,例如@Override标记重写父类方法或实现接口方法,@Test标记单元测试方法,所以我们可以简单地把它理解为一种有特殊 ...
- Hibernate(2)映射文件Xxx-hbm.xml
1.Hibernate映射文件Xxx-hbm.xml ①POJO 类和关系数据库之间的映射可以用一个XML文档来定义.通过 POJO 类的数据库映射文件,Hibernate可以理解持久化类和数据表之间 ...
- myeclipse中hibernate生成映射文件
在hibernate中,每个数据表对应的其实是一个实体类,每个实体类有一个对应的hbm.xml配置文件匹配,myeclipse中有个MyEclipse Database Explorer视图,它提供了 ...
随机推荐
- Resharper 8.2 注册码
用户名:ronle注册码:ZoJzmeVBoAv9Sskw76emgksMMFiLn4NM
- ubuntu不能正常登录
在ubuntu登录界面,输入密码后,出现一个界面后一闪而过又返回登录界面.查看auth.log发现如下错误 May 15 15:42:19 tim-vm lightdm: pam_unix(light ...
- LeetCode Intersection of Two Arrays II
原题链接在这里:https://leetcode.com/problems/intersection-of-two-arrays-ii/ 题目: Given two arrays, write a f ...
- MyEclipse 及Tomcate 安装 配置
使用的工具为myeclipse-pro-2014-GA-offline-installer-windows(需安装).apache-tomcat-6.0.37.jdk1.6.0.14. 1.MyEcl ...
- wdcp安装
下载安装(ssh登录服务器,执行如下操作即可,需要用到root用户权限来安装)v3版本已经发布,更多可看论坛 wdCP v3版本讨论区更多安装请看 http://www.wdlinux.cn/bbs/ ...
- CXF WebService整合SpringMVC的maven项目
首先推荐博客:http://www.cnblogs.com/xdp-gacl/p/4259481.html http://blog.csdn.net/hu_shengyang/article/de ...
- ios cell时间相同隐藏算法
- iOS,视图相关
1.移除视图的所以子视图 2.自定义视图(UIView) 3.处理悬浮窗口(类似微信视频),等比缩放 4.自定义前面视图(可以手写字) 5.图片拉伸的几种方式,计算文本占用空间大小 6.UILable ...
- poj 2393 Yogurt factory
http://poj.org/problem?id=2393 Yogurt factory Time Limit: 1000MS Memory Limit: 65536K Total Submis ...
- C++之路进阶——poj3461(Oulipo)
Oulipo Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 35694 Accepted: 14424 Descript ...