1. 概述
Hibernate映射类型分为两种:内置映射类型和客户化映射类型。
内置类型负责把一些常见的java类型映射到相应的SQL类型。String到varchar的映射如图1所示:
图1-1 hibernate内置类型string完成String到varchar的映射
客户化映射类型可以把用户定义的java类型映射到数据表的相应字段。通过实现Hibernate的UserType接口。
2. 内置映射类型
(此处内容仅为以后设计做参考)
2.1 基本类型的Hibernate映射类型
表2-1基本类型的Hibernate映射类型
2.2 java日期和时间类型的Hibernate映射
表2-2 Java日期和时间类型的Hibernate映射类型
2.3 Java大对象类型的Hibernate映射
表2-3 Java大对象类型的Hibernate映射
2.4 JDK自带的个别Java类的Hibernate映射类型
表2-4JDK自带的个别Java类的Hibernate映射类型
3. 客户化映射类型
Hibernate提供了客户化的映射类型接口,允许用户以编程的方式实现把持久化类的任意类型的属性映射到数据库中。
如下面的AddressUserType实现了将Address型的属性映射到数据库。
package mypack;
import org.hibernate.*;
import org.hibernate.usertype.*;
import java.sql.*;
import java.io.Serializable;
public class AddressUserType implements UserType {
private static final int[] SQL_TYPES = {Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR};
public int[] sqlTypes() { return SQL_TYPES; }
public Class returnedClass() { return Address.class; }
public boolean isMutable() { return false; }
public Object deepCopy(Object value) {
return value; // Address is immutable
}
public boolean equals(Object x, Object y) {
if (x == y) return true;
if (x == null || y == null) return false;
return x.equals(y);
}
public int hashCode(Object x){
return x.hashCode();
}
public Object nullSafeGet(ResultSet resultSet,String[] names, Object owner)
throws HibernateException, SQLException {
String province = resultSet.getString(names[0]);
String city = resultSet.getString(names[1]);
String street = resultSet.getString(names[2]);
String zipcode = resultSet.getString(names[3]);
if(province ==null && city==null && street==null && zipcode==null)
return null;
return new Address(province,city,street,zipcode);
}
public void nullSafeSet(PreparedStatement statement,Object value,int index)
throws HibernateException, SQLException {
if (value == null) {
statement.setNull(index, Types.VARCHAR);
statement.setNull(index+1, Types.VARCHAR);
statement.setNull(index+2, Types.VARCHAR);
statement.setNull(index+3, Types.VARCHAR);
} else {
Address address=(Address)value;
statement.setString(index, address.getProvince());
statement.setString(index+1, address.getCity());
statement.setString(index+2, address.getStreet());
statement.setString(index+3, address.getZipcode());
}
}
public Object assemble(Serializable cached, Object owner){
return cached;
}
public Serializable disassemble(Object value) {
return (Serializable)value;
}
public Object replace(Object original,Object target,Object owner){
return original;
}
}
有兴趣的读者可以研究一下其中的实现过程。
4. 用客户化映射类型取代Hibernate组件
4.1 区分可变类和不可变类
可变类:创建了实例后,可以修改它的属性;
不可变类:当创建了这种类的实例后,就不许修改它的属性。其设计模式:
- 属性定义为private final。
- 不对外公开setXXX()方法(即不编写此方法)。
- 只对外公开getXXX()方法。
- 允许构造方法中设置所有的属性。
- 覆盖Object类的equals()和hashCode()方法。
Java中的基本类型的包装类都是不可变类,所以这里的Address类也必须是不可变类。(数据类型当然不可更改)
4.2 实现映射
- 定义一个Hibernate映射类型AddressUserType(如上面所示),它把Address类型的属性映射到数据库。
- 修改Monkey.hfg.xml,使用客户化映射类型AddressUserType映射Monkey类中的Address类型属性到数据库。
映射homeAddress的代码:
<property name="homeAddress" type="mypack.AddressUserType" >
<column name="HOME_PROVINCE" />
<column name="HOME_CITY" />
<column name="HOME_STREET"/>
<column name="HOME_ZIPCODE" />
</property>
4.3 比较Hibernate组件映射和客户化映射类型映射
Hibernate组件和客户化映射类型那个都是值类型。
- Hibernate组件采用的是xml配置方式,具有较好的可维护性;
- 客户化映射类型采用的是编程方式,能够完成更加复杂灵活的映射。