Hibernate映射类型分为两种:内置映射类型和客户化映射类型,内置映射类型负责把常见的java类型映射到相应的sql类型;另外,用户可以实现UserType或CompositeUserType接口,来定制客户化映射类型,这样可以把用户定义 的java类型映射到数据库表的相应字段。
1、内置映射类型
1.1 java基本类型的hibernate映射类型
1.2 java时间和日期类型的hibernate映射类型
1.3 Java大对象类型的hibernate映射类型
注意:不允许使用这些数据类型来定义持久化类的OID。
CLOB:字符串大对象(Character Large Object)
BLOB:表示二进制大对象(Binary Large Object)
MySql中不支持标准SQL的CLOB类型,MySQL中使用TEXT,MEDIUMTEXT,LONGTEXT类型类表示长度超过255的长文本数据,分别为0~65535,0~16777215,0~4294967295字节。
如果持久化类的某个字段为java.sql.Clob或java.sql.Blob实例时,映射设置如下:
<property name="description" type="clob" column="DESCRIPTION">
在应用程序中通过Hibernate来保存java.sql.Clob或java.sql.Blob实例时,必须包括以下两个步骤:
a. 在数据库事务中先保存一个空的Blob或Clob实例。
b. 接着锁定这条记录,更新在a中保存的实例,把二进制数据或长文本数据写到Blob或Clob实例中。
例:
Session session = sessionFactory.openSession();
Transaction tx = session.begainTransaction();
customer = new Customer();
//现保存空的clob实例
customer.setDescription(Hibernate.createClob(" "));
session.save(customer);
session.flush();
//锁定这条记录
session.refresh(customer,LockMode.UPGRADE);
oracle.sql.Clob clob = (Oracle.sql.Clob)customer.getDescription();
//把长文本数据写到Clob实例中
java.io.Writer.pw=clob.getCharacterOutputStream();
pw.write(longText);//longText表示一个长度〉255的字符串
pw.close();
tx.commit();
session.close();
尽管java.sql.Clob和java.sql.Blob是处理java大对象的有效方式,但是使用二者受到以下两点限制:
a. 如果在持久化类中定义了一个该类型的属性,只有在一个数据库事务中,这样的实例才会有效。
b. 有些数据库系统的jdbc驱动程序不支持这样的类型。
如果在java程序中处理图片或长文件的二进制数据,使用byte[]比Blob更方便,处理长度>255的字符串使用String比Clob更方便。
1.4 JDK自带的个别java类的hibernate映射类型
1.5 使用映射类型
在以下情况下必须显示指定映射文件中的hibernate映射类型:
a. 如果希望通过hbm2java工具由映射文件来生成持久化类,必须在映射文件中显式指定映射类型
b. 一个java类型对应多个Hibernate映射类型的场合。如:java.util.Date,可以对应Hibernate的映射类型中的date,time,timestamp。
2、客户化映射类型
2.1 用户化映射类型取代Hibernate组件
曾经用组件来映射Customer类的Address类型的homeAddress属性和comAddress属性,同样可以用自定义映射类型来实现。
把Address设计为不可变类,即当创建了这种类的实例以后,就不允许修改它的属性。java中所有基本类型的包装类都是不可变类:Integer,Long等。创建用户自己的不可变类时,可以考虑以下设计模式:
a. 把属性定义为private final类型。
b. 不对外公开set方法
c. 只对外公开get方法
d. 允许在构造方法中设置所有属性。
e. 覆盖Object类的equals和hashCode方法,在equals方法中根据对象的属性值来比较两个对象是否相等,保证用equals方法比较相等的两个对象的hashCode方法返回值也相等。
package mypack;
import java.io.Serializable;
public class Address implements Serializable ...{
private final String province;
private final String city;
private final String street;
private final String zipcode;
public Address(String province, String city, String street, String zipcode) ...{
this.street = street;
this.city = city;
this.province = province;
this.zipcode = zipcode;
}
public String getProvince() ...{
return this.province;
}
public String getCity() ...{
return this.city;
}
public String getStreet() ...{
return this.street;
}
public String getZipcode() ...{
return this.zipcode;
}
public boolean equals(Object o)...{
if (this == o) return true;
if (!(o instanceof Address)) return false;
final Address address = (Address) o;
if(!province.equals(address.province)) return false;
if(!city.equals(address.city)) return false;
if(!street.equals(address.street)) return false;
if(!zipcode.equals(address.zipcode)) return false;
return true;
}
public int hashCode()...{
int result;
result= (province==null?0:province.hashCode());
result = 29 * result + (city==null?0:city.hashCode());
result = 29 * result + (street==null?0:street.hashCode());
result = 29 * result + (zipcode==null?0:zipcode.hashCode());
return result;
}
}
package mypack;
import net.sf.hibernate.*;
import java.sql.*;
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 Object nullSafeGet(ResultSet resultSet,
String[] names,
Object owner)
throws HibernateException, SQLException ...{
if (resultSet.wasNull()) return null;
String province = resultSet.getString(names[0]);
String city = resultSet.getString(names[1]);
String street = resultSet.getString(names[2]);
String zipcode = resultSet.getString(names[3]);
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());
}
}
}
<property name="homeAddress" type="mypack.AddressUserType" >
<column name="HOME_STREET" length="15" />
<column name="HOME_CITY" length="15" />
<column name="HOME_PROVINCE" length="15" />
<column name="HOME_ZIPCODE" length="6" />
</property>
<property name="comAddress" type="mypack.AddressUserType" >
<column name="COM_STREET" length="15" />
<column name="COM_CITY" length="15" />
<column name="COM_PROVINCE" length="15" />
<column name="COM_ZIPCODE" length="6" />
</property>
注:映射文件列的顺序要与自定义type中的列名对应顺序一致,如果不一致可能会取出的数据没错,但是库表中的数据列的位置不一致,同时可能出现类型不匹配。能取出一致数据的地原因是nullSafeSet和nullSafeGet中列的顺序一致!