Hibernate识别数据库特有字段实例详解
Hibernate识别数据库特有字段实例详解
前言:
Hibernate已经为绝大多数常用的数据库数据类型提供了内置支持,但对于某些数据库的专属字段支持就不够好了。这些特殊数据类型往往提供了比常规数据类型更好的数据表达能力,更符合我们的业务场景。比如PostgreSQL的Interval类型,可以非常方便的保存一个时间段的数据。本文以添加Interval类型支持为例,说明为Hibernate添加特有数据类型支持的方法。
Hibernate提供了丰富的数据类型支持,但对于部分数据库专有的数据类型,提供的支持就很有限了。比如PostgreSQL的Interval类型,对于保存一个"时间段"数据就非常方便。
在开发中,我们期望将Interval类型映射为Java8的Duration类型。但是Hibernate默认对Duration类型的映射是直接映射到数据库的BigInt类型,直接保存纳秒值。显然对于不直接支持Interval类型的数据库来说,是比较合适的,但是我们仍然期望直接映射到数据库的Interval类型。
为此,我们需要调整Hibernate对于两种数据类型(Java世界的Duration和Db世界的Interval)的映射关系。
幸运的是,Hibernate提供了非常方便的方法可以实现数据类型的映射。
为此,我们需要一个实现org.hibernate.usertype.UserType接口的类,来实现两个世界的数据转换/映射工作。
Hibernate的自定义类型(UserType)
UserType是Hibernate提供的一个自定义数据类型的接口。所有自定义数据均需实现此接口,或者从org.hibernate.usertype中定义的接口中选择一个合适的接口。
鉴于我们的场景比较简单,直接实现UserType即可满足需求。此接口提供了如下一组方法需要自己实现:
assemble(Serializablecached,Objectowner)
从序列化中重新构建(Java)对象。
deepCopy(Objectvalue)
返回深度副本。
disassemble(Objectvalue)
转换对象的序列化数据。
equals(Objectx,Objecty)
返回两个映射的数据是否相等。
hashCode(Objectx)
获取对象的散列。
isMutable()
返回对象是否是可变类型。
nullSafeGet(ResultSetrs,String[]names,Objectowner)
从数据库类型的数据,返回对应的Java对象。核心实现方法
nullSafeSet(PreparedStatementst,Objectvalue,intindex)
从Java对象,返回对应的数据库类型的数据。核心实现方法
replace(Objectoriginal,Objecttarget,Objectowner)
合并期间,将实体中的目标值(target)替换为原始值(original)。
returnedClass()
nullSafeGet返回的类。
sqlTypes()
返回对应的数据库类型。
实例
packageframework.postgresql; importorg.hibernate.HibernateException; importorg.hibernate.engine.spi.SharedSessionContractImplementor; importorg.hibernate.usertype.UserType; importorg.postgresql.util.PGInterval; importjava.io.Serializable; importjava.sql.PreparedStatement; importjava.sql.ResultSet; importjava.sql.SQLException; importjava.sql.Types; importjava.time.Duration; /** *PostgreSqlInteval字段与java.time.Duration映射 *目前只支持到最多1个月(30天)的间隔 **使用方法: *在实体类上增加 *\@TypeDef(name="interval",typeClass=IntervalType.class) *在字段定义上增加: *\@Type(type="interval") *
*http://stackoverflow.com/questions/1945615/how-to-map-the-type-interval-in-hibernate/6139581#6139581 * *@version1.0 *@since1.0 */ publicclassIntervalTypeimplementsUserType{ publicObjectassemble(Serializablecached,Objectowner)throwsHibernateException{ returncached; } publicObjectdeepCopy(Objectvalue)throwsHibernateException{ returnvalue; } publicSerializabledisassemble(Objectvalue)throwsHibernateException{ return(Serializable)value; } publicbooleanequals(Objectarg0,Objectarg1)throwsHibernateException{ returnarg0!=null&&arg1!=null&&arg0.equals(arg1)||arg0==null&&arg1==null; } publicinthashCode(Objectobject)throwsHibernateException{ returnobject.hashCode(); } @Override publicObjectnullSafeGet(ResultSetresultSet,String[]names,SharedSessionContractImplementorsessionImplementor,Objecto)throwsHibernateException,SQLException{ Stringinterval=resultSet.getString(names[0]); if(resultSet.wasNull()||interval==null){ returnnull; } PGIntervalpgInterval=newPGInterval(interval); returngetDuration(pgInterval); } @Override publicvoidnullSafeSet(PreparedStatementst,Objectvalue,intindex,SharedSessionContractImplementorsessionImplementor)throwsHibernateException,SQLException{ if(value==null){ st.setNull(index,Types.OTHER); }else{ //thishttp://postgresql.1045698.n5.nabble.com/Inserting-Information-in-PostgreSQL-interval-td2175203.html#a2175205 Durationduration=(Duration)value; st.setObject(index,getInterval(duration),Types.OTHER); } } publicstaticDurationgetDuration(PGIntervalpgInterval){ returnDuration.ofSeconds(pgInterval.getDays()*24*3600+ pgInterval.getHours()*3600+ pgInterval.getMinutes()*60+ (int)pgInterval.getSeconds()); } privatestaticPGIntervalgetInterval(Durationvalue){ longseconds=value.getSeconds(); intdays=(int)(seconds/(24*3600)); seconds-=days*24*3600; inthours=(int)(seconds/3600); seconds-=hours*3600; intminutes=(int)(seconds/60); seconds-=minutes*60; seconds=Math.abs(seconds); returnnewPGInterval(0,0,days,hours,minutes,seconds); } publicbooleanisMutable(){ returnfalse; } publicObjectreplace(Objectoriginal,Objecttarget,Objectowner)throwsHibernateException{ returnoriginal; } publicClassreturnedClass(){ returnDuration.class; } publicint[]sqlTypes(){ returnnewint[]{Types.OTHER}; } }
使用自定义类型
至此,我们已经定义好了自己的数据类型。但Hibernate还不知道怎么使用它。为此,我们需要通过在Entity上使用使用TypeDef注解,并在属性上使用Type注解。
比如:
... @Entity @TypeDef(name="interval",typeClass=IntervalType.class) publicclassPaperStatisimplementsSerializable{ ... @Column(name="avg_duration") @Type(type="interval") publicDurationgetAvgDuration(){ returnthis.avgDuration; } ... }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!