Hibernate学习笔记(四)深入理解Hibernate的映射文件

  • 映射文件结构
  • 映射主键
  • 映射普通属性
  • 映射集合属性
  • 集合属性的性能分析
  • 有序集合映射
  • 映射数据库对象


映射文件结构:
xx.hbm.xml映射文件结构为:
<hibernate-mapping >
     <class />
     <class />
</hibernate-mapping>
<hibernate-mapping ../>标签可以有下列若干个重要属性:
schema:指定所映射数据库的Schema名,如果指定了该属性,则表名会自动添加该Schema前缀。
catalog:指定所映射数据库的Catalog名,如果指定了该属性,则表名会自动添加该Catalog前缀。
deault-cascade:设置Hibernate默认的级联风格,该属性的默认值是none。当配置Java属性映射和集合映射时还可指定cascade属性,用于覆盖默认的级联风格。
default-access:指定Hibernate默认的属性访问策略,默认值为property,即使用getter/setter方法来访问属性。如果指定access="field",则Hibernate通过反射来访问成员变量。也可以自己定义属性访问策略,但需要自己提供PropertyAccessor接口的实现类,然后在access中设定自己定义的属性访问策略的类名称。
default-lazy:设置Hibernate默认的延迟加载策略,默认值为true,即默认启用延迟加载策略。通常情况下不应该关闭延迟加载策略。
auto-import:设置是否允许在查询语言中使用非全限定的类名(仅限于本映射文件中的类)。该属性默认值为true,如果同一个映射文件中有两个持久化类的类名一样,则必须设置该属性为false,否则Hibernate无法区别这两个类,而抛出异常。
package:对映射文件中<class ../>标签中name属性中没有给定全限定的类名时,会在类名中加上该package前缀。如果不给出package属性值的话,会抛java.lang.ClassNotFoundException。

<class ../>标签可以有下列若干个重要属性:
name 属性时最重要的属性,不可缺少的,是用来指定该配置文件中POJO类名。
schema、catalog、lazy三个属性是用来覆盖<hibernate-mapping ../>标签中指定的默认属性值的。
table:指定该持久化类映射的表名。省略的话,以该持久化类名作为表名。mysql中为类的小写名称,别的数据库未做测试。
discriminator-value:指定区分不同子类的值,当使用<subclass ../>元素来定义持久化类的继承关系映射时需要使用该属性。
mutable:用于指定持久化类实例是可变对象还是不可变对象,该属性只能接受true和false,属性默认值是true。
proxy:指定一个接口,在延迟装载时作为代理使用,也可以在这里指定该类自己的名字。
dynamic-update:指定用于更新记录的update语句是否在运行时动态生成,并且只更新哪些改变过的字段。该属性默认值为false,开启该属性将导致Hibernate需要更多的时间来生成SQL语句。
select-before-update:设置为true的话,则Hibernate只有在当前对象被修改过是才会使用update语句来保存其状态。默认是false。
使用此属性会降低性能,通常用作状态很少发生改变,程序却又经常需要保存的对象。
polymorphism:当采用<union-subclass../>元素来配置继承映射时,该元素指定是否需要采用隐式多态查询。该属性的默认值为implicit。
where:相当于where子句,当指定了该属性,则不论使用load还是get方法,只要试图加载该持久化对象,都会加上该where条件。
persister:指定一个定制的ClassPersister。
batch-size:根据标识符(identifier)来抓取实例时每批抓取实例数,默认值为1。
optimistic-lock:该属性指定乐观锁定策略。属性默认值是version。
check:指定一个SQL表达式,用于为该持久化类所对应的表指定一个多行的Check约束。
subselect:该属性用于映射不可变的、只读的实体。通俗地说,就是将数据库的子查询映射成Hibernate持久化对象。当需要使用视图来代替数据表时,该属性比较有用。

映射主键:
标识属性通过<id../>元素来指定,该元素可以有以下属性:
name:对应持久化类标识属性名。该属性可选,如果不指定,则表示该持久化类没有标识属性。
type:可以省略,省略的话Hibernate会自行判断该标识属性的数据类型,通常建议设置该属性,以保证更好的性能。可以是Hibernate的内建类型,或者Java类型,Java类型需要加上全限定类名。
column:映射标识属性对应的数据库的列名,默认属性名和列名相同。
access:指定Hibernate访问该标识属性的访问策略,默认是property。用户覆盖<hibernate-mapping ../>元素的default-access属性。

物理主键、逻辑主键:
数据库建模理论推荐不要使用具有实际意义的物理主键,而是用没有任何实际意义的逻辑主键。

主键生成器负责生成数据库表记录的主键,通常有以下常见的主键生成器:
increment:为short、long int类型主键生成唯一标识,只有在没有其他进程往同一张表插入数据时才能使用,在集群情况下不要使用。
identity:为db2 、mysql 、sql server、sybase、HypersonicSQL数据库提供自增长的主键。返回标识属性是long、short、int类型的。
sequence:DB2 、PostgreSQL、Oracle、SAP DB、McKoi等提供sequence支持。返回标识属性是long、short、int类型的。
hilo:使用一个高/低位算法高效生成long、short或int类型的标识符。该标识属性值在一个特定的数据库是唯一的。
seqhilo:使用一个高/低位算法高效生成long、short或int类型的标识符,需要给定一个数据库sequence名。它会将主键历史状态保存在Sequence中,适用于支持Sequence的数据库,如Oracle。
uuid:用一个128位的UUID算法生成字符串类型的标识符,这在一个网络中唯一的。
guid:在sql server 、mysql中使用数据库生成的GUID字符串。应该是适用于字符串类型的标识属性。
native:根据底层数据库的能力选择identity、sequence或者hilo中的一个。
assigned:让程序在save()之前为对象分配一个标识符,相当于不指定<generator../>元素时所采用的默认策略。
select:通过数据库触发器旋转某个唯一主键的行,并返回其主键值作为标识属性值。
foreign:表名直接使用另一个关联的对象的标识属性值(即本持久化对象不能生成主键)。这种主键生成器只有在基于主键的1-1关联映射中才有用。

映射普通属性:
Hibernate使用<property../>元素来映射普通属性,通常有以下常见属性:
name:持久化类的属性名。
column:列名,不指定的话,默认列名和属性名相同。
formula:该属性指定一个SQL表达式,指定该属性的值将根据表达式来计算,形式为formula="(sql)",英文括号不能省略。
access:定义Hibernate访问该属性的访问策略,默认是property。用于覆盖根元素<hibernate-mapping../>中的default-access属性。
lazy:是否启动延迟加载,默认是false。
unique:设置是否为该属性所映射的数据库列添加唯一约束。如果设置为true,则此字段可以作为集合属性映射时<key../>标签的property-ref引用的目标。
optimistic-lock:设置该属性在进行更新时是否需要使用乐观锁定,该属性默认是true。当属性为true时,当该属性的值发生改变时,该持久化对象的版本值将会增长。
generated:设置该属性映射的数据库列的值是否由数据库生成。属性值可以为never、insert、always。never:不由数据库生成。insert:该属性值时insert时生成,但不会在update时重新生成。always:该属性值在insert和update时都会被重新生成。
index:为该属性对应数据库列添加一个索引,指定索引的名称。
unique_key:指定一个唯一键的名称,当Hibernate自动建表时,为该属性映射的列创建一个唯一索引。
length:指定数据库列的长度。

映射主键和映射普通属性实例:
<hibernate-mapping package="org.crazyit.app.domain">
	<!-- 每个class元素对应一个持久化对象 -->
	<class name="Person" table="person_inf">
		<!-- id元素定义持久化类的标识属性 -->
		<id name="id" column="person_id">
			<generator class="identity"/>
		</id>
		<!-- property元素定义常规属性 -->
		<property name="name" type="string" not-null="true"/>
		<property name="age" type="int" />
	</class>
</hibernate-mapping>

映射集合属性:
(1)、Hibernate要求集合属性需要用接口来定义类型。
集合属性的元素有如下几个:
list:用于映射List集合属性。
set:用于映射Map集合属性。
map:用于映射Map集合属性。
array:用于映射数组集合属性。
rimitive-array:专门用于映射基本数据类型的数组。
bag:用于映射无序集合。
idbag:用于映射无序集合,但为集合增加逻辑次序。

集合属性映射示例:
POJP类(Person.java):
public class Person {
	private int id;
	private String name;
	private int age;
	private List<String> schools = new ArrayList<String>();
	private String[] schools2 ;
	private Set<String> schools3 = new HashSet<String>();
	private Collection<String> schools4 = new ArrayList<String>(); 
	private Map<String,Float> scores = new HashMap<String,Float>();
	//省略属性的getter和setter方法
}
映射文件(Person.hbm.xml):
<hibernate-mapping package="org.crazyit.app.domain">
	<class name="Person" table="person_inf">
		<id name="id" column="person_id">
			<generator class="identity"/>
		</id>
		<property name="name" type="string" not-null="true"/>
		<property name="age" type="int" />
		<list name="schools" table="school">
			<key column="personid" not-null="true"></key>
			<list-index column="list_order"></list-index>
			<element type="string" column="school_name"></element>
		</list>
		<array name="schools2" table="school2">
			<key column="personid" not-null="true"></key>
			<list-index column="list_order"></list-index>
			<element type="string" column="school_name"></element>
		</array>
		<set name="schools3" table="school3">
			<key column="personid" not-null="true"></key>
			<element type="string" column="school_name" not-null="true"></element>
		</set>
		<bag name="schools4" table="school4" >
			<key column="personid" not-null="true" ></key>
			<element type="string" column="school_name" not-null="true"></element>
		</bag>
		<map name="scores" table="score">
			<key column="personid" not-null="true"></key>
			<map-key column="subject" type="string"></map-key>
			<element column="grade" type="float"></element>
		</map>
	</class>
</hibernate-mapping>

工具类(MyHibernateUtil.java):我们工具类中使用currSession()方法返回一个线程安全的Session对象。
package lee;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class MyHibernateUtil {

	private static SessionFactory sf;
	static{
		Configuration config = new Configuration().configure();
		sf = config.buildSessionFactory();
	}
	
	private static ThreadLocal<Session> session = new ThreadLocal<Session>();
	public static Session currSession() {
		if(session.get() ==null) {
			Session s  = sf.openSession();
			session.set(s);
		}
		return session.get();
	}
	
	public static void closeSession(){
		if(session.get()!=null) {
			session.get().clear();
			session.set(null);
		}
	}
}
测试结果(控制台打印为):
INFO: HHH000227: Running hbm2ddl schema export
Hibernate: 
2015-4-23 20:27:12 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: HHH000389: Unsuccessful: 
2015-4-23 20:27:12 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: Can not issue empty query.
Hibernate: alter table school drop foreign key FK_48amgp8tko414xxqs1q1vaat4
Hibernate: alter table school2 drop foreign key FK_7fcimegwyk7gom5o477j87mo2
Hibernate: alter table school3 drop foreign key FK_i05kci2iyrwtlm1lyu3hycpe0
Hibernate: alter table school4 drop foreign key FK_h6kwlvuuc17bvp62v3p0a73pe
Hibernate: alter table score drop foreign key FK_fj132ki110acgdgsu1gyy3va7
Hibernate: alter table training drop foreign key FK_5qwb2jw7h91pyv85lxtx49jp8
Hibernate: drop table if exists news_table
Hibernate: drop table if exists person_inf
Hibernate: drop table if exists school
Hibernate: drop table if exists school2
Hibernate: drop table if exists school3
Hibernate: drop table if exists school4
Hibernate: drop table if exists score
Hibernate: drop table if exists training
Hibernate: create table news_table (id integer not null auto_increment, title varchar(255) not null, content varchar(255), primary key (id)) type=InnoDB
Hibernate: create table person_inf (person_id integer not null auto_increment, name varchar(255) not null, age integer, primary key (person_id)) type=InnoDB
Hibernate: create table school (personid integer not null, school_name varchar(255), list_order integer not null, primary key (personid, list_order)) type=InnoDB
Hibernate: create table school2 (personid integer not null, school_name varchar(255), list_order integer not null, primary key (personid, list_order)) type=InnoDB
Hibernate: create table school3 (personid integer not null, school_name varchar(255) not null, primary key (personid, school_name)) type=InnoDB
Hibernate: create table school4 (personid integer not null, school_name varchar(255) not null) type=InnoDB
Hibernate: create table score (personid integer not null, grade float, subject varchar(255) not null, primary key (personid, subject)) type=InnoDB
Hibernate: create table training (personid integer not null, training_name varchar(255) not null, primary key (personid, training_name)) type=InnoDB
Hibernate: alter table school add constraint FK_48amgp8tko414xxqs1q1vaat4 foreign key (personid) references person_inf (person_id)
Hibernate: alter table school2 add constraint FK_7fcimegwyk7gom5o477j87mo2 foreign key (personid) references person_inf (person_id)
Hibernate: alter table school3 add constraint FK_i05kci2iyrwtlm1lyu3hycpe0 foreign key (personid) references person_inf (person_id)
Hibernate: alter table school4 add constraint FK_h6kwlvuuc17bvp62v3p0a73pe foreign key (personid) references person_inf (person_id)
Hibernate: alter table score add constraint FK_fj132ki110acgdgsu1gyy3va7 foreign key (personid) references person_inf (person_id)
Hibernate: alter table training add constraint FK_5qwb2jw7h91pyv85lxtx49jp8 foreign key (personid) references person_inf (person_id)
Hibernate: create table test(t_name varchar(255)) ;
2015-4-23 20:27:15 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: HHH000389: Unsuccessful: create table test(t_name varchar(255)) ;
2015-4-23 20:27:15 org.hibernate.tool.hbm2ddl.SchemaExport perform
ERROR: Table 'test' already exists
2015-4-23 20:27:15 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: HHH000230: Schema export complete
Hibernate: /* insert org.crazyit.app.domain.Person */ insert into person_inf (name, age) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools */ insert into school (personid, list_order, school_name) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools */ insert into school (personid, list_order, school_name) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools2 */ insert into school2 (personid, list_order, school_name) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools2 */ insert into school2 (personid, list_order, school_name) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools3 */ insert into school3 (personid, school_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools3 */ insert into school3 (personid, school_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools4 */ insert into school4 (personid, school_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.schools4 */ insert into school4 (personid, school_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.scores */ insert into score (personid, subject, grade) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.scores */ insert into score (personid, subject, grade) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.scores */ insert into score (personid, subject, grade) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.scores */ insert into score (personid, subject, grade) values (?, ?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.trainings */ insert into training (personid, training_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.trainings */ insert into training (personid, training_name) values (?, ?)
我们看数据库分别存着下列表,school1为list映射建的表,school2为数组映射建的表,school3为Set映射建的表,school4为抽象集合Collection映射建的表,score为Map集合映射建立的表,数据如图所示:




(2)、集合元素有以下属性:
name:对应该集合属性的名称。
table:保存集合属性的表名。如果不指定该属性,则表名为主表名_集合属性名,如 person_inf_scores。
lazy:设置是否启动延迟加载,默认是true,即大多数操作不会初始化集合类(适用于非常大的集合)。
inverse:指定该集合关联的实体在双向关联关系中不控制关联关系。
casecade:指定对持久化对象的持久化操作(如save、update、delete)是否会级联到他所关联的子实体。
order-by:该属性用于设置数据库对集合元素排序,该属性仅对1.4或更高版本JDK有效。该属性的值为指定表的指定字段(一个或者几个)加上asc或者desc关键字,这种排序是数据库进行SQL查询时进行排序的,而不是直接在内存中排序。如本文下面介绍有序集合映射时设置<set name="trainings" table="training" order-by="training desc" >

(3)、集合元素映射的表需要一个外键,使用<key../>来定义,<key../>标签可以有以下属性:
column:指定外键字段的列名。
on-delete:指定外键约束是否打开数据库级别的级联删除。
property-ref:指定外键应用主键是否为原表的主键。如果省略的话,表示使用主表的主键作为外键,也可以指定为其他非空字段,如property-ref="name"。
not-null:指定外键列是否具有非空约束,如果指定非空约束,则意味着无论何时,外键总是主键的一部分。
update:指定外键列是否可更新,如果不允许更新, 则意味着无论何时,外键总是主键的一部分。
unique:指定外键列是否具有唯一约束,如果指定唯一约束, 则意味着无论何时,外键总是主键的一部分。

(4)、除了<set../><bag../>元素外,其他标签都需要为集合属性的数据表指定一个索引列——用于保存数组索引,或者List索引,或者Map集合的key索引。用于映射索引列的元素有如下几个:
<list-index../>:用于映射List集合、数组的索引列。
<map-key../>:用于映射Map集合,基础数据类型的索引列。
<map-key-many-to-many../>:用于映射Map集合,实体引用类型的索引列。
<composite-map-key..>:用于映射Map集合、复合数据类型的索引列。

(5)、Hibernate集合元素数据类型可以是任意数据类型,包括基础类型、字符串、日期、自定义类型、复合类型以及其他持久化对象的引用。如果集合元素时基本数据类型、字符串、日期、自定义类型、复合类型等,则位于集合中的对象可能根据“值”语义来操作(其生命周期完全依赖于集合持有者,必须通过集合持有者来访问这些集合);如果集合元素是其他持久化对象的引用,此时就变成了关联映射(关联关系映射时会重点介绍),那么这些集合元素都具有自己的生命周期。
根据集合元素的数据类型的不同,用于映射集合元素大致包括以下几种元素:
<element../>:当集合元素是基本类型及其包装类、字符串、日期类型时使用该元素。
<composite-element../>:当集合元素时复合类型时,使用该元素。
<one-to-many../>或<many-to-many../>:当集合元素是其他持久化对象的引用时使用它们。这两个元素主要是用于进行关联关系映射的。

(6)、下面分别介绍不同集合属性的配置:
List集合属性:<list name="" table=""><key column="" /><list-index column=""/><element type="" column=""  /></list>
数组属性:<array name="" table=""><key column="" /><list-index column=""/><element type="" column=""  /></array>
Set集合属性:<set name="" table=""><key column="" /><element type="" column=""  /></set>
bag元素映射:映射抽象的集合,如POJO中定义如下:private Collection<String> schools = new ArrayList<String>();
<bag name="" table=""><key column="" /><element type="" column=""  /></bag>
Map集合属性:type="string"。"string"必须是小写
<map name="" table=""><key column="" /><may-key column="" type="string"/><element type="" column=""  /></map>

集合属性的性能分析:
1、对于集合属性通常采用延迟加载策略,当需要使用集合属性时,才从数据看装载关联数据。数组虽然也是有序集合,但是数组无法使用延迟加载(因为数组的长度不可变)。所以数组作为集合的性能并不高,通常我们认为List、Map集合性能较高,而Set紧随其后。
2、集合分为以下两大类:有序集合(集合里的元素可以根据key或index访问),无序集合(集合里的元素只能遍历)。
对于有序集合,由于外键列和集合元素索引列组成联合主键,所以集合属性的更新非常高效。当需要更新或者删除一行数据时,可以寻找找到该行数据。
对于无序集合,例如Set的主键是由<key../>和其他元素字段构成,或者没有主键。如果集合中元素时组合元素或者大文本、大二进制字段,数据库可能无法有效对复杂的主键进行索引。即使可以建立索引,性能也是非常差。其中<bag../>映射效率是最差的,因为他允许有重复的元素值,也没有索引,所以不可能定义主键。Hibernate无法判断重复行,所以修改集合属性时,Hibernate会先删除全部集合,再重新创建集合对应表和插入数据,效率非常低下。
综上所述,有序集合的属性在添加、删除、修改中有用较好的性能表现。
3、在设计良好的Hibernate领域模型中,1-N关联的1的一端通常带有inverse="true",对于这种关联关系,1的一端不再控制关联关系,所有的更新操作将会在N的一端进行处理,对于这种情况,无须考虑其集合的更新性能。 一旦我们指定了inverse="true"属性,这时使用<list../>和<bag../>映射属性将有较高的性能。
4、当我们试图删除集合中全部元素时,Hibernate不需要一条一条的delete每行数据,而是使用一条delete语句直接完成。
但是如果要删除绝大部分集合元素,如删除一个长度为20的集合类,如果要删除其中19个集合元素,只剩下一个集合元素。这时我们期望Hibernate能够先调用一条delete语句删除全部集合元素,再调用insert插入一条记录。但是Hibernate却只是逐个删除19个需要删除的数据,这将产生19条delete语句。
这是我们可以使用一个技巧来优化,先设置集合属性为null,在设置集合属性为仅有的内容。如:
person.setSchools(null); person.setSchools(tmp); 其中tmp为需要保留在集合中的属性。
		Person rmd = (Person) sess.get(Person.class, 1);
		rmd.setScores(null);
		Map<String ,Float> map = new HashMap<String ,Float>();
		map.put("Chinese" , 67f);
		rmd.setScores(map);

有序集合映射:
Hibernate还支持使用SortedSet和SortedMap两个有序集合,当我们需要映射这种有序集合时,应该为<map../>元素或<set../>元素指定sort属性,该属性可以是如下三个值:
unsorted:映射有序集合时不排序。
natural:映射有序集合时使用自然排序。
java.util.Comparator实现类的类名:使用排序器对有序集合元素进行定制排序。
POJO:
public class Person {
	private int id;
	private String name;
	private int age;
	private SortedSet<String> trainings = new TreeSet<String>();
	//省略属性的getter和setter方法
}
映射文件:
<hibernate-mapping package="org.crazyit.app.domain">
	<class name="Person" table="person_inf">
		<id name="id" column="person_id">
			<generator class="identity"/>
		</id>
		<property name="name" type="string" not-null="true"/>
		<property name="age" type="int" />
		<set name="trainings" table="training" sort="natural" order-by="training_name desc">
			<key column="personid" not-null="true"></key>
			<element type="string" column="training_name" not-null="true"></element>
		</set>
	</class>
</hibernate-mapping>
测试类(PersonManager.java):
public class PersonManager {
<span style="white-space:pre">	</span>public static void main(String[] args) {
<span style="white-space:pre">		</span>Session sess = MyHibernateUtil.currSession();
<span style="white-space:pre">		</span>Transaction tx = sess.beginTransaction();
<span style="white-space:pre">		</span>Person rmd = new Person();
<span style="white-space:pre">		</span>rmd.setName("ReMinD");
<span style="white-space:pre">		</span>rmd.setAge(26);
<span style="white-space:pre">		</span>SortedSet<String> trainings = new TreeSet<String>();
<span style="white-space:pre">		</span>trainings.add("Wild Java Camp");
<span style="white-space:pre">		</span>trainings.add("Sun SCJP");
<span style="white-space:pre">		</span>trainings.add("Z");
<span style="white-space:pre">		</span>trainings.add("A");
<span style="white-space:pre">		</span>rmd.setTrainings(trainings);
<span style="white-space:pre">		</span>sess.save(rmd);
<span style="white-space:pre">		</span>
//<span style="white-space:pre">		</span>Person rmd = (Person) sess.get(Person.class, 1);
//<span style="white-space:pre">		</span>System.out.println(rmd.getTrainings().toString());
<span style="white-space:pre">		</span>tx.commit();
<span style="white-space:pre">		</span>MyHibernateUtil.closeSession();
<span style="white-space:pre">	</span>}
}
测试添加后的结果:
INFO: HHH000232: Schema update complete
Hibernate: /* insert org.crazyit.app.domain.Person */ insert into person_inf (name, age) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.trainings */ insert into training (personid, training_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.trainings */ insert into training (personid, training_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.trainings */ insert into training (personid, training_name) values (?, ?)
Hibernate: /* insert collection row org.crazyit.app.domain.Person.trainings */ insert into training (personid, training_name) values (?, ?)
可以看到我们插入了四条记录,如下图所示:

下面我们注释掉测试代码的上部分,打开注释掉的代码,来测试查询出这四条记录,我们来看看打印的SQL为:
INFO: HHH000232: Schema update complete
Hibernate: select person0_.person_id as person_i1_0_0_, person0_.name as name2_0_0_, person0_.age as age3_0_0_ from person_inf person0_ where person0_.person_id=?
Hibernate: select trainings0_.personid as personid1_0_0_, trainings0_.training_name as training2_1_0_ from training trainings0_ where trainings0_.personid=? order by trainings0_.training_name asc
[A, Sun SCJP, Wild Java Camp, Z]
这里测试无论在映射文件里是asc排序还是desc排序,输出结果都一样,不明白为什么,从下图可以看出排序应该没生效,但是where子句中加上了order by 语句了。



如果我们将Person中的SortedSet 改为Set,后续程序不变,测试出查询记录没有排序,且where子句中没有加order by 语句,如下所示:
Hibernate: select person0_.person_id as person_i1_0_0_, person0_.name as name2_0_0_, person0_.age as age3_0_0_ from person_inf person0_ where person0_.person_id=?
Hibernate: select trainings0_.personid as personid1_0_0_, trainings0_.training_name as training2_1_0_ from training trainings0_ where trainings0_.personid=?
[Sun SCJP, A, Wild Java Camp, Z]



映射数据库对象:
通过映射数据库对象,可以使用映射文件来创建和删除触发器、存储过程等数据库对象,以及数据库建表等操作,只要是java.sql.Statement.execute()方法中执行的SQL语句都可以在此使用。Hibernate提供<database-object../>元素来满足这种需求。
使用<database-object../>元素有如下两种形式:
1、在映射文件中显示声明create和drop命令:
<hibernate-mapping>
     <database-object>
          <create>create trigger t_full_content_gen.. </create>
          <drop> drop trigger t_full_content_gen  </drop>
          <!-- 指定仅对MySQL数据库有效 -->
          <dialect-scope name="org.hibernate.dialect.MySQLDialect"/>
          <dialect-scope name="org.hibernate.dialect.MySQLInnoDBDialect"/>
     </database-object>
</hibernate-mapping>
注意每个<database-object../>元素中只有一组<create../>、<drop../>对。如果想指定某些数据库对象仅在特定方言中才可以使用,还可以在<database-object>元素里使用<dialect-scope../>子元素来进行配置。

2、提供一个类,这个类知道如何组织create和drop命令。这个类必须实现org.hibernate.mapping.AuxiliaryDatabaseObject接口。
<hibernate-mapping>
     <database-object>
          <definition class="MyTriggerDefinition" />
     </database-object>
</hibernate-mapping>

下例为使用Hibernate映射文件来创建一个数据库表:
<hibernate-mapping package="org.crazyit.app.domain">
	<database-object>
		<create>create table test(t_name varchar(255)) ;</create>
		<drop></drop>
		<dialect-scope name="org.hibernate.dialect.MySQLDialect" />
		<dialect-scope name="org.hibernate.dialect.MySQLInnoDBDialect" />
	</database-object>
</hibernate-mapping>
注意即使<drop></drop>没有内容也不能省略,不然会报错误的,如图所示。

使用测试类来创建建表语句:
public class SchemaExportTest {
	Random random = new Random();
	public static void main(String[] args) {
//		Configuration conf = new Configuration().configure();
//		SessionFactory sf = conf.buildSessionFactory();
//		sf.close();
		
		Configuration conf = new Configuration().configure();
		SchemaExport se = new SchemaExport(conf);
		se.setFormat(true).setOutputFile("new.sql").create(true, true);
	}
}
上面两种方法都可以自动创建表,第一种是生成SessionFactory对象时,测试了一下即使配置文件指定hbm2ddl.auto属性值为update,只要数据库表不存在,也会自动创建表。第二种是使用SchemaExport对象来自动创建表,还可以将建表语句输入到项目路径下的new.sql文件中。
    alter table school 
        drop 
        foreign key FK_48amgp8tko414xxqs1q1vaat4

    alter table school2 
        drop 
        foreign key FK_7fcimegwyk7gom5o477j87mo2

    alter table school3 
        drop 
        foreign key FK_i05kci2iyrwtlm1lyu3hycpe0

    alter table school4 
        drop 
        foreign key FK_h6kwlvuuc17bvp62v3p0a73pe

    alter table score 
        drop 
        foreign key FK_fj132ki110acgdgsu1gyy3va7

    alter table training 
        drop 
        foreign key FK_5qwb2jw7h91pyv85lxtx49jp8

    drop table if exists news_table

    drop table if exists person_inf

    drop table if exists school

    drop table if exists school2

    drop table if exists school3

    drop table if exists school4

    drop table if exists score

    drop table if exists training

    create table news_table (
        id integer not null auto_increment,
        title varchar(255) not null,
        content varchar(255),
        primary key (id)
    ) type=InnoDB

    create table person_inf (
        person_id integer not null auto_increment,
        name varchar(255) not null,
        age integer,
        primary key (person_id)
    ) type=InnoDB

    create table school (
        personid integer not null,
        school_name varchar(255),
        list_order integer not null,
        primary key (personid, list_order)
    ) type=InnoDB

    create table school2 (
        personid integer not null,
        school_name varchar(255),
        list_order integer not null,
        primary key (personid, list_order)
    ) type=InnoDB

    create table school3 (
        personid integer not null,
        school_name varchar(255) not null,
        primary key (personid, school_name)
    ) type=InnoDB

    create table school4 (
        personid integer not null,
        school_name varchar(255) not null
    ) type=InnoDB

    create table score (
        personid integer not null,
        grade float,
        subject varchar(255) not null,
        primary key (personid, subject)
    ) type=InnoDB

    create table training (
        personid integer not null,
        training_name varchar(255) not null,
        primary key (personid, training_name)
    ) type=InnoDB

    alter table school 
        add constraint FK_48amgp8tko414xxqs1q1vaat4 
        foreign key (personid) 
        references person_inf (person_id)

    alter table school2 
        add constraint FK_7fcimegwyk7gom5o477j87mo2 
        foreign key (personid) 
        references person_inf (person_id)

    alter table school3 
        add constraint FK_i05kci2iyrwtlm1lyu3hycpe0 
        foreign key (personid) 
        references person_inf (person_id)

    alter table school4 
        add constraint FK_h6kwlvuuc17bvp62v3p0a73pe 
        foreign key (personid) 
        references person_inf (person_id)

    alter table score 
        add constraint FK_fj132ki110acgdgsu1gyy3va7 
        foreign key (personid) 
        references person_inf (person_id)

    alter table training 
        add constraint FK_5qwb2jw7h91pyv85lxtx49jp8 
        foreign key (personid) 
        references person_inf (person_id)

    create table test(
        t_name varchar(255)
    ) ;



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值