精通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中列的顺序一致!