Hibernate识别数据库特有字段实例详解
hibernate识别数据库特有字段实例详解
前言:
hibernate已经为绝大多数常用的数据库数据类型提供了内置支持,但对于某些数据库的专属字段支持就不够好了。 这些特殊数据类型往往提供了比常规数据类型更好的数据表达能力,更符合我们的业务场景。比如postgresql的interval类型,可以非常方便的保存一个时间段的数据。 本文以添加interval类型支持为例,说明为hibernate添加特有数据类型支持的方法。
hibernate提供了丰富的数据类型支持,但对于部分数据库专有的数据类型,提供的支持就很有限了。比如postgresql的interval类型,对于保存一个"时间段"数据就非常方便。
在开发中,我们期望将interval类型映射为java 8 的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(serializable cached, object owner)
从序列化中重新构建(java)对象。
deepcopy(object value)
返回深度副本。
disassemble(object value)
转换对象的序列化数据。
equals(object x, object y)
返回两个映射的数据是否相等。
hashcode(object x)
获取对象的散列。
ismutable()
返回对象是否是可变类型。
nullsafeget(resultset rs, string[] names, object owner)
从数据库类型的数据,返回对应的java对象。核心实现方法
nullsafeset(preparedstatement st, object value, int index)
从java对象,返回对应的数据库类型的数据。核心实现方法
replace(object original, object target, object owner)
合并期间,将实体中的目标值(target)替换为原始值(original)。
returnedclass()
nullsafeget返回的类。
sqltypes()
返回对应的数据库类型。
实例
package framework.postgresql; import org.hibernate.hibernateexception; import org.hibernate.engine.spi.sharedsessioncontractimplementor; import org.hibernate.usertype.usertype; import org.postgresql.util.pginterval; import java.io.serializable; import java.sql.preparedstatement; import java.sql.resultset; import java.sql.sqlexception; import java.sql.types; import java.time.duration; /** * postgresql inteval字段与java.time.duration映射 * 目前只支持到最多1个月(30天)的间隔 * <p> * 使用方法: * 在实体类上增加 * \@typedef(name="interval", typeclass = intervaltype.class) * 在字段定义上增加: * \@type(type = "interval") * <p> * http://*.com/questions/1945615/how-to-map-the-type-interval-in-hibernate/6139581#6139581 * * @version 1.0 * @since 1.0 */ public class intervaltype implements usertype { public object assemble(serializable cached, object owner) throws hibernateexception { return cached; } public object deepcopy(object value) throws hibernateexception { return value; } public serializable disassemble(object value) throws hibernateexception { return (serializable) value; } public boolean equals(object arg0, object arg1) throws hibernateexception { return arg0 != null && arg1 != null && arg0.equals(arg1) || arg0 == null && arg1 == null; } public int hashcode(object object) throws hibernateexception { return object.hashcode(); } @override public object nullsafeget(resultset resultset, string[] names, sharedsessioncontractimplementor sessionimplementor, object o) throws hibernateexception, sqlexception { string interval = resultset.getstring(names[0]); if (resultset.wasnull() || interval == null) { return null; } pginterval pginterval = new pginterval(interval); return getduration(pginterval); } @override public void nullsafeset(preparedstatement st, object value, int index, sharedsessioncontractimplementor sessionimplementor) throws hibernateexception, sqlexception { if (value == null) { st.setnull(index, types.other); } else { //this http://postgresql.1045698.n5.nabble.com/inserting-information-in-postgresql-interval-td2175203.html#a2175205 duration duration = (duration) value; st.setobject(index, getinterval(duration), types.other); } } public static duration getduration(pginterval pginterval) { return duration.ofseconds(pginterval.getdays() * 24 * 3600 + pginterval.gethours() * 3600 + pginterval.getminutes() * 60 + (int) pginterval.getseconds()); } private static pginterval getinterval(duration value) { long seconds = value.getseconds(); int days = (int) (seconds / (24 * 3600)); seconds -= days * 24 * 3600; int hours = (int) (seconds / 3600); seconds -= hours * 3600; int minutes = (int) (seconds / 60); seconds -= minutes * 60; seconds = math.abs(seconds); return new pginterval(0, 0, days, hours, minutes, seconds); } public boolean ismutable() { return false; } public object replace(object original, object target, object owner) throws hibernateexception { return original; } public class returnedclass() { return duration.class; } public int[] sqltypes() { return new int[]{types.other}; } }
使用自定义类型
至此,我们已经定义好了自己的数据类型。但hibernate还不知道怎么使用它。为此,我们需要通过在entity上使用使用typedef注解,并在属性上使用type注解。
比如:
... @entity @typedef(name = "interval", typeclass = intervaltype.class) public class paperstatis implements serializable { ... @column(name = "avg_duration") @type(type = "interval") public duration getavgduration() { return this.avgduration; } ... }
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
下一篇: maya怎么创建摇椅模型?