本文作者:佚名

Hibernate识别数据库特有字段实例详解

佚名 2019-04-25 854
摘要:Hibernate识别数据库特有字段实例详解前言: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.postgresqlimport org.hibernate.HibernateExceptionimport org.hibernate.engine.spi.SharedSessionContractImplementorimport org.hibernate.usertype.UserTypeimport org.postgresql.util.PGIntervalimport java.io.Serializableimport java.sql.PreparedStatementimport java.sql.ResultSetimport java.sql.SQLExceptionimport java.sql.Typesimport java.time.Durationpublic 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 }...}

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

未经允许不得转载:

作者:佚名,标题:Hibernate识别数据库特有字段实例详解,原文地址:https://www.vfjianzhan.com/java/201904/2839.html发布于2019-04-25
转载或复制请以超链接形式并注明出处DESTOON

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏