Hibernate
有两种映射类型,一种是内置映射类型,它把一些常见的
JAVA
类型映射到相应的
SQL
类型,另一种是客户化映射类型,它把用户定义的
JAVA
类型映射到数据库表的相应字段
Hibernate
的内置映射类型
1
JAVA
基本类型
(
包括它们的包装类
)
和
Hibernate
映射类型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2
JAVA
时间和日期类型的
Hibernate
映射类
型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
在标准
SQL
中,
DATE
表示日期
(2005-01-09)
,
TIME
表示时间
(11:46:54)
,
TIMESTAMP
表示时间戳,包含日期和时间信息
(20050109114654),
如果没有显式插入,由系统自动添加当前系统时间
3
Java
大对象类型的
Hibernate
映射类型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MySQL
不支持标准
SQL
的
CLOB
类型。
通过
Hibernate
来保存
java.sql.Clob
或
java.sql.Blob
实例时,发须包含两个步骤:
(1)
在一个数据库事务中先保存一个空的
Blob
或
Clob
实例
(2)
锁定记录,更新上一步保存的
Bolb
或
Clob
实例,把二进制数或长文本写进去,如:
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)
Blob
和
Clob
实例只有在一个数据库事务中才有效
(2)
有些数据库的
JDBC
驱动程序不支持
java.sql.Blob
或
java.sq.Clob
。如果在
Java
应用中处理图片或长文件的二进制数用
byte[]
比
java.sql.Blob
方便
;
如果处理长度超过
255
的字符串
java.lang.String
比
java.sql.Clob
更方法
JDK
自带的个别
JAVA
类的
Hibernate
映射类型
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
使用
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>