• 企业400电话
  • 微网小程序
  • AI电话机器人
  • 电商代运营
  • 全 部 栏 目

    企业400电话 网络优化推广 AI电话机器人 呼叫中心 网站建设 商标✡知产 微网小程序 电商运营 彩铃•短信 增值拓展业务
    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://stackoverflow.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;
     }
    ...
    }
    

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

    您可能感兴趣的文章:
    • Hibernate迫切连接和普通连接的区别实例详解
    • hibernate通过session实现增删改查操作实例解析
    • 在已有spring的基础上集成hibernate的实例讲解
    • hibernate属性级别注解实例代码
    • Hibernate 修改数据的实例详解
    • JSP开发之hibernate之单向多对一关联的实例
    • hibernate4快速入门实例详解
    • Hibernate初体验及简单错误排除代码详解
    上一篇:Spring AOP切面解决数据库读写分离实例详解
    下一篇:详解 hibernate mapping配置
  • 相关文章
  • 

    © 2016-2020 巨人网络通讯 版权所有

    《增值电信业务经营许可证》 苏ICP备15040257号-8

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