1. 映射文件
hibernate-mapping-3.0.dtd,位于“/src/org/hibernate”下。
2. 类映射
2.1 抽象类映射
抽象类Container的定义如下:
package com.weportal.container;


/** *//**
* @hibernate.class
* table = "CONTAINER"
* @hibernate.discriminator
* column = "CONTAINER_TYPE"
* type = "String"
*/

public abstract class Container ...{
private String containerId;
private double size;
private String name;
private String description;

/** *//**
* @hibernate.id
* generator-class = "hilo"
*/

public String getContainerId() ...{
return containerId;
}

/** *//**
* @hibernate.property
*/

public String getName() ...{
return name;
}

/** *//**
* @hibernate.property
*/

public String getDescription() ...{
return description;
}

/** *//**
* @param description The description to set.
*/

public void setDescription(String description) ...{
this.description = description;
}

/** *//**
* @param name The name to set.
*/

public void setName(String name) ...{
this.name = name;
}

/** *//**
* @return Returns the size.
* @hibernate.property
*/

public double getSize() ...{
return size;
}

/** *//**
* @param size The size to set.
*/

public void setSize(double size) ...{
this.size = size;
}


/** *//**
* @param containerId The containerId to set.
*/

public void setContainerId(String containerId) ...{
this.containerId = containerId;
}
}
Box和Bottle类的定义如下:
package com.weportal.container;

/** *//**
* @hibernate.subclass
* discriminator-values = "BOX"
*/

public class Box extends Container ...{
private double height;
private double length;
private double width;

/** *//**
* @hibernate.property
*/

public double getLength() ...{
return length;
}

/** *//**
* @hibernate.property
*/

public double getWidth() ...{
return width;
}

/** *//**
* @hibernate.property
*/

public double getHeight() ...{
return height;
}

/** *//**
* @param height The height to set.
*/

public void setHeight(double height) ...{
this.height = height;
}


/** *//**
* @param length The length to set.
*/

public void setLength(double length) ...{
this.length = length;
}


/** *//**
* @param width The width to set.
*/

public void setWidth(double width) ...{
this.width = width;
}
}
package com.weportal.container;


/**//**
* @hibernate.subclass
* discriminator-values = "BOTTLE"
*/

public class Bottle extends Container ...{
private double diameter;
private double height;

/**//**
* @return Returns the diameter.
* @hibernate.property
*/

public double getDiameter() ...{
return diameter;
}

/**//**
* @param diameter The diameter to set.
*/

public void setDiameter(double diameter) ...{
this.diameter = diameter;
}

/**//**
* @return Returns the height.
* @hibernate.property
*/

public double getHeight() ...{
return height;
}

/**//**
* @param height The height to set.
*/

public void setHeight(double height) ...{
this.height = height;
}

}
映射文件Container.hbm.xml如下:
Container类的主键id,生成主键所使用的generator是uuid,uuid是利用128位的UUID算法生成的字符串来作为主键。而native表示主键的生成由数据库底层去选择算法。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.weportal.container">
<class name="Container">
<id name="containerId" type="string">
<generator class="uuid"></generator>
</id>
<discriminator column="CONTAINER_TYPE"></discriminator>
<property name="size"></property>
<property name="name"></property>
<property name="description"></property>
<subclass name="Box" discriminator-value="BOX">
<property name="height"></property>
<property name="length"></property>
<property name="width"></property>
</subclass>
<subclass name="Bottle" discriminator-value="BOTTLE">
<property name="diameter"></property>
<property name="height"></property>
</subclass>
</class>
</hibernate-mapping>
使用下面的类来自动生成数据库表(so cool!),
package com.weportal;

import org.apache.log4j.PropertyConfigurator;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.cfg.Environment;


public class DatabaseGenerate ...{


public static void main(String[] args) ...{
DatabaseGenerate idbg = new DatabaseGenerate();
idbg.generate(true);
}

public void generate(boolean create)...{
PropertyConfigurator.configure("log4j.Properties");
Configuration cfg = new Configuration();
cfg.configure();

if(create)...{
cfg.setProperty(Environment.HBM2DDL_AUTO, "create-drop");
}
SessionFactory sf = cfg.buildSessionFactory();
}
}
生成的表container的定义如下:
create table `hibernate`.`container`(
`containerId` varchar(255) default '' not null,
`CONTAINER_TYPE` varchar(255) default '' not null,
`size` double,
`name` varchar(255),
`description` varchar(255),
`height` double,
`length` double,
`width` double,
`diameter` double,
primary key (`containerId`)
);

create unique index `PRIMARY` on `hibernate`.`container`(`containerId`);
观察上表,container中既包含了Container中的属性,也包含了Box和Bottle两个之类中的属性,它们共享这个表。
2.1.1 主键ID
可以自定义一个org.hibernate.id.IdentifierGenerator接口的实现类作为主键ID的generator,例如下面的代码使用的是IP和当前的时间混合来作为ID。
package com.weportal.generator;

import java.io.Serializable;
import java.net.InetAddress;
import java.net.UnknownHostException;

import org.hibernate.HibernateException;
import org.hibernate.engine.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;


public class MyGenerator implements IdentifierGenerator ...{


/**//* (non-Javadoc)
* @see org.hibernate.id.IdentifierGenerator#generate(org.hibernate.engine.SessionImplementor, java.lang.Object)
*/
public Serializable generate(SessionImplementor session, Object obj)

throws HibernateException ...{
StringBuilder sb = new StringBuilder();

try ...{
sb.append(InetAddress.getLocalHost().getAddress().toString());

} catch (UnknownHostException e) ...{
e.printStackTrace();
}
sb.append(System.currentTimeMillis());
return sb.toString();
}


/**//* (non-Javadoc)
* @see org.hibernate.id.IdentifierGenerator#generate(org.hibernate.engine.SessionImplementor, java.lang.Object, java.lang.String)
*/
public Serializable generate(SessionImplementor session, Object obj,

String entity) throws HibernateException ...{
StringBuilder sb = new StringBuilder();

try ...{
sb.append(InetAddress.getLocalHost().getAddress().toString());

} catch (UnknownHostException e) ...{
e.printStackTrace();
}
sb.append(System.currentTimeMillis());
return sb.toString();
}
}

利用MyGenerator代替Container中的“uuid”,
<id name="containerId" type="string">
<generator class="com.weportal.generator.MyGenerator"></generator>
</id>
hibernate自带的generator如下:
generator | 算法说明 |
foreign | 使用另外一个相关联的对象的标识符作为主键 |
assigned | 主键由外部程序负责生成,在 save() 之前指定一个 |
hilo | 通过hi/lo 算法实现的主键生成机制,需要额外的数据库表或字段提供高位值来源 |
seqhilo | 与hilo 类似,通过hi/lo 算法实现的主键生成机制,需要数据库中的 Sequence,适用于支持 Sequence 的数据库,如Oracle |
increment | 主键按数值顺序递增。此方式的实现机制为在当前应用实例中维持一个变量,以保存着当前的最大值,之后每次需要生成主键的时候将此值加1作为主键。这种方式可能产生的问题是:不能在集群下使用 |
identity | 采用数据库提供的主键生成机制。如DB2、SQL Server、MySQL 中的主键生成机制 |
sequence | 采用数据库提供的 sequence 机制生成主键。如 Oralce 中的Sequence |
native | 由 Hibernate 根据使用的数据库自行判断采用 identity、hilo、sequence 其中一种作为主键生成方式 |
uuid.hex | 由 Hibernate 基于128 位 UUID 算法 生成16 进制数值(编码后以长度32 的字符串表示)作为主键 |
uuid.string |
与uuid.hex 类似,只是生成的主键未进行编码(长度16),不能应用在 PostgreSQL 数据库中
|
2.1.2 where属性
利用where属性可以选出hibernate感兴趣的数据,在提取时只将这些数据映射为类的实例导出。
例如:
<class name="Container" where="size < 1000">
下面的代码检索出的结果是size < 1000 的记录。
package com.weportal.container;

import java.util.Iterator;
import java.util.List;

import org.apache.log4j.PropertyConfigurator;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;


public class ContainerView ...{


public static void main(String[] args) ...{
PropertyConfigurator.configure("log4j.Properties");
Configuration cfg = new Configuration();
cfg.configure();
SessionFactory sf = cfg.buildSessionFactory();
Session sess = sf.openSession();
List pcs = sess.createQuery("from Container").list();
if (pcs.isEmpty())
System.out.println("没数据");

for (Iterator it = pcs.iterator(); it.hasNext();) ...{
Container cter = (Container) it.next();
//System.out.println(cter.getClass().getName());
System.out.println("id : " + cter.getContainerId());
System.out.println("name : " + cter.getName());
System.out.println("size : " + cter.getSize());
}
sess.close();
}
}