精通hibernate学习笔记(6)[映射类型]

Hibernate映射类型分为两种:内置映射类型和客户化映射类型,内置映射类型负责把常见的java类型映射到相应的sql类型;另外,用户可以实现UserType或CompositeUserType接口,来定制客户化映射类型,这样可以把用户定义 的java类型映射到数据库表的相应字段。

1、内置映射类型

1.1java基本类型的hibernate映射类型

1.2java时间和日期类型的hibernate映射类型

1.3Java大对象类型的hibernate映射类型

注意:不允许使用这些数据类型来定义持久化类的OID。

CLOB:字符串大对象(CharacterLargeObject)

BLOB:表示二进制大对象(BinaryLargeObject)

MySql中不支持标准SQL的CLOB类型,MySQL中使用TEXT,MEDIUMTEXT,LONGTEXT类型类表示长度超过255的长文本数据,分别为0~65535,0~16777215,0~4294967295字节。

如果持久化类的某个字段为java.sql.Clob或java.sql.Blob实例时,映射设置如下:

<propertyname="description"type="clob"column="DESCRIPTION">

在应用程序中通过Hibernate来保存java.sql.Clob或java.sql.Blob实例时,必须包括以下两个步骤:

a.在数据库事务中先保存一个空的Blob或Clob实例。

b.接着锁定这条记录,更新在a中保存的实例,把二进制数据或长文本数据写到Blob或Clob实例中。

例:

Sessionsession=sessionFactory.openSession();

Transactiontx=session.begainTransaction();

customer=newCustomer();

//现保存空的clob实例

customer.setDescription(Hibernate.createClob(""));

session.save(customer);

session.flush();

//锁定这条记录

session.refresh(customer,LockMode.UPGRADE);

oracle.sql.Clobclob=(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.4JDK自带的个别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.把属性定义为privatefinal类型。

b.不对外公开set方法

c.只对外公开get方法

d.允许在构造方法中设置所有属性。

e.覆盖Object类的equals和hashCode方法,在equals方法中根据对象的属性值来比较两个对象是否相等,保证用equals方法比较相等的两个对象的hashCode方法返回值也相等。

packagemypack;

importjava.io.Serializable;

publicclassAddressimplementsSerializable...{

privatefinalStringprovince;

privatefinalStringcity;

privatefinalStringstreet;

privatefinalStringzipcode;

publicAddress(Stringprovince,Stringcity,Stringstreet,Stringzipcode)...{

this.street=street;

this.city=city;

this.province=province;

this.zipcode=zipcode;

}

publicStringgetProvince()...{

returnthis.province;

}

publicStringgetCity()...{

returnthis.city;

}

publicStringgetStreet()...{

returnthis.street;

}

publicStringgetZipcode()...{

returnthis.zipcode;

}

publicbooleanequals(Objecto)...{

if(this==o)returntrue;

if(!(oinstanceofAddress))returnfalse;

finalAddressaddress=(Address)o;

if(!province.equals(address.province))returnfalse;

if(!city.equals(address.city))returnfalse;

if(!street.equals(address.street))returnfalse;

if(!zipcode.equals(address.zipcode))returnfalse;

returntrue;

}

publicinthashCode()...{

intresult;

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());

returnresult;

}

}

packagemypack;

importnet.sf.hibernate.*;

importjava.sql.*;

publicclassAddressUserTypeimplementsUserType...{

privatestaticfinalint[]SQL_TYPES=...{Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR};

publicint[]sqlTypes()...{returnSQL_TYPES;}

publicClassreturnedClass()...{returnAddress.class;}

publicbooleanisMutable()...{returnfalse;}

publicObjectdeepCopy(Objectvalue)...{

returnvalue;//Addressisimmutable

}

publicbooleanequals(Objectx,Objecty)...{

if(x==y)returntrue;

if(x==null||y==null)returnfalse;

returnx.equals(y);

}

publicObjectnullSafeGet(ResultSetresultSet,

String[]names,

Objectowner)

throwsHibernateException,SQLException...{

if(resultSet.wasNull())returnnull;

Stringprovince=resultSet.getString(names[0]);

Stringcity=resultSet.getString(names[1]);

Stringstreet=resultSet.getString(names[2]);

Stringzipcode=resultSet.getString(names[3]);

returnnewAddress(province,city,street,zipcode);

}

publicvoidnullSafeSet(PreparedStatementstatement,Objectvalue,intindex)

throwsHibernateException,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...{

Addressaddress=(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());

}

}

}

<propertyname="homeAddress"type="mypack.AddressUserType">

<columnname="HOME_STREET"length="15"/>

<columnname="HOME_CITY"length="15"/>

<columnname="HOME_PROVINCE"length="15"/>

<columnname="HOME_ZIPCODE"length="6"/>

</property>

<propertyname="comAddress"type="mypack.AddressUserType">

<columnname="COM_STREET"length="15"/>

<columnname="COM_CITY"length="15"/>

<columnname="COM_PROVINCE"length="15"/>

<columnname="COM_ZIPCODE"length="6"/>

</property>

注:映射文件列的顺序要与自定义type中的列名对应顺序一致,如果不一致可能会取出的数据没错,但是库表中的数据列的位置不一致,同时可能出现类型不匹配。能取出一致数据的地原因是nullSafeSet和nullSafeGet中列的顺序一致!

相关推荐