Hibernate有两种映射类型,一种是内置映射类型,它把一些常见的JAVA类型映射到相应的SQL类型,另一种是客户化映射类型,它把用户定义的JAVA类型映射到数据库表的相应字段
Hibernate的内置映射类型
1 JAVA基本类型(包括它们的包装类)和Hibernate映射类型
Hibernate | Java类型 | 标准SQL类型 | 大小和取值范围 |
integer/int | int/java.lang.Integer | integer | 4字节,-2^31~2^31-1 |
long | long/java.lang.Long | bigint | 8字节, -2^63~2^63-1 |
short | short/java.lang.Short | smallint | 2字节, -2^15~2^15-1 |
byte | byte/java.lang.Byte | tinyint | 1字节, -128~127 |
flat | float/java.lang.Float | float | 4字节, |
double | double/java.lang.Double | double | 8字节, 双精度浮点数 |
big_decimal | java.math.BigDecimal | numeric | 用法:numeric(8,2) |
character | char/…Character/…String | char(1) | 定长字符 |
string | java.lang.String | varchar | 变长字符串 |
boolean | boolean/java.lang.Boolean | bit | 布尔类型 |
yes_no | boolean/java.lang.Boolean | char(1)(‘Y’/’N’) | 布尔类型 |
true_false | boolean/java.lang.Boolean | char(1)(‘T’/’F’) | 布尔类型 |
2 JAVA时间和日期类型的Hibernate映射类型
映射类型 | java类型 | 标准SQL类型 | 描述 |
date | java.util.Date/java.sql.Date | date | 日期,形式:yyyy-mm-dd |
time | java.util.Date/java.sql.Time | time | 时间,形式:hh:mm:ss |
timestamp | …Date/java.sql.Timestamp | timestamp | 形式:yyyymmddhhmmss |
calendar | java.util.Calendar | timestamp | 时间和日期,形式同上 |
calendar_date | java.util.Calendar | date | 日期,形式:yyyy-mm-dd |
在标准SQL中,DATE表示日期(2005-01-09),TIME表示时间(11:46:54),TIMESTAMP表示时间戳,包含日期和时间信息(20050109114654),如果没有显式插入,由系统自动添加当前系统时间
3 Java大对象类型的Hibernate映射类型
映射类型 | Java类型 | 标准SQL类型 | 描述 |
binary | byte[] | varbinary/blob | 存放二进制数 |
text | java.lang.String | clob | 字符串大对象 |
serializable | 实现java.io.Serializable接口的类 | varbinary/blob | |
clob | java.sql.Clob | clob | 字符串大对象 |
bolb | java.sql.Blob | blob | 二进制大对象 |
MySQL不支持标准SQL的CLOB类型。
通过Hibernate来保存java.sql.Clob或java.sql.Blob实例时,发须包含两个步骤:
(1)
(2)
Customer customer=new Customer();
customer.setDescription(Hibernate.createClob(“”));//保存一个空的Clob实例
session.save(customer);
session.flush();
session.refresh(customer,LockMode.UPGRADE);//锁定记录
oracle.sql.CLOB clob=(oracle.sql.CLOB)customer.getDescription();
java.io.Writer pw=clob.getCharacterOutputStream();
pw.write(longText);//lognText变量表示长度超过255的字符串
pw.close();
tx.commit();
session.close();
以上不用java.sql.Blob和java.sql.Clob处理JAVA大对有以下两个原因:
(1)
(2)
JDK自带的个别JAVA类的Hibernate映射类型
映射类型 | Java类型 | 标准SQL类型 |
class | java.lang.Class | VARCHAR |
locale(现场) | java.util.Locale | VARCHAR |
timezone(地区) | java.util.TimeZone | VARCHAR |
currency(流通) | java.utilCurrency | VARCHAR |
使用Hibernate内置映射类型
有的数据库并不支持所有的标准SQL类型,如Oracle开发了变长字符串varchar2 来代替varchar.怎样使Hibernate可以使用标准的SQL类型来生成DML(Date Manipulation Language)?(如我在<column>的sql-type中用标准的SQL类型,要它生成底层数据库支持的类型.Manipulation:处理.)
解决方案:Java应用通过Hibernate访问数据库,而Hibernate又通过JDBC驱动程序访数据库,JDBC对底层数据库SQL类型进行封装,向上提供标准的SQL类型接口,这样Hibernate就可以根据底层数据库使用的SQL方言,把标准SQL类型翻译成底成数据库类型。如:<property name=”email” type=”string” length=”50”>如果连接的是Oracle,hbm2ddl生成的脚本为…carchar2(50).由string->标准SQL varchar->Oracle varchar2
一个java类型对应多个Hibernate映射类型的场合。例如,如果持久化类的属性为java.util.Date类型,对应的Hibernate映射类型可以是date,time或timestamp。此时必须根据对应的数据库表的字段的SQL类型,来确定Hibernate映射类型。如果字段为Date类型,则hibernate映射为datge,如果为TIME则为time,如果为TIMESTAMP则为timestamp。
客户化映射类型
Hiberante提供了客户化映射类型接口(net.sf.hibernate.UserType或CompositeUserType),允许用户创建自定义的映射类型,把持久化类的任意类型的属性映射到数据库中
Address.java
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;
}
}
AddressUserType类的源程序,它实现了UserType接口
package mypack;
import org.hibernate.*;
import org.hibernate.usertype.*;
import java.sql.*;
public class AddressUserType implements UserType {
/** 设置和Address类的四个属性province、city、street和zipcode对应
的字段的SQL类型,它们均为VARCHAR类型 */
private static final int[] SQL_TYPES =
{Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR};
public int[] sqlTypes() { return SQL_TYPES; }
/** 设置AddressUserType所映射的Java类:Address类 */
public Class returnedClass() { return Address.class; }
/** 指明Address类是不可变类 */
public boolean isMutable() { return false; }
/** 返回Address对象的快照,由于Address类是不可变类,
因此直接将参数代表的Address对象返回 */
public Object deepCopy(Object value) {
return value;
}
/** 比较一个Address对象是否和它的快照相同 */
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();
}
/** 从JDBC ResultSet中读取province、city、street和zipcode,
然后构造一个Address对象*/
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]);
if(province ==null && city==null && street==null
&& zipcode==null)
return null;
return new Address(province,city,street,zipcode);
}
/** 把Address对象的属性添加到JDBC PreparedStatement中 */
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;
}
}
创建了以上的AddressUserType后,就可以按以下方式映射Customer类的homeAddress和comAddress属性
<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>