SoFunction
Updated on 2025-03-08

Detailed explanation of Hibernate identification of database-specific field instances

Detailed explanation of Hibernate identification of database-specific field instances

Preface:

Hibernate already provides built-in support for most commonly used database data types, but it is not good enough for some databases' exclusive field support. These special data types often provide better data expression capabilities than regular data types and are more in line with our business scenarios. For example, the Interval type of PostgreSQL can easily save data for a period of time. This article uses the example of adding Interval type support to illustrate how to add unique data type support to Hibernate.
Hibernate provides rich data type support, but the support provided is very limited for some database proprietary data types. For example, the Interval type of PostgreSQL is very convenient for saving a "time period" data.

In development, we expect to map the Interval type to the Duration type of Java 8. However, Hibernate's default mapping of Duration type is directly mapped to the BigInt type of the database, and directly saves the nanosecond value. Obviously, it is more appropriate for databases that do not directly support Interval type, but we still expect to map directly to the Interval type of database.

To do this, we need to adjust the mapping relationship of Hibernate for two data types (Duration in the Java world and Interval in the Db world).

Fortunately, Hibernate provides a very convenient way to implement mapping of data types.

To do this, we need a class that implements interfaces to implement data conversion/mapping work in both worlds.

Hibernate's custom type (UserType)

UserType is an interface for custom data types provided by Hibernate. All custom data need to implement this interface, or select a suitable interface from the interface defined therein.

Given that our scenario is relatively simple, directly implementing UserType can meet the needs. This interface provides the following set of methods that need to be implemented by yourself:

assemble(Serializable cached, Object owner)

Rebuild (Java) objects from serialization.

deepCopy(Object value)

Return to the depth copy.

disassemble(Object value)

Convert the serialized data of the object.

equals(Object x, Object y)

Returns whether the data of the two maps are equal.

hashCode(Object x)

Get the hash of the object.

isMutable()

Returns whether the object is of a mutable type.

nullSafeGet(ResultSet rs, String[] names, Object owner)

From database type data, return the corresponding Java object. Core implementation method

nullSafeSet(PreparedStatement st, Object value, int index)

From a Java object, return data of the corresponding database type. Core implementation method

replace(Object original, Object target, Object owner)

During the merge, replace the target value in the entity with the original value.

returnedClass()

nullSafeGet returns the class.

sqlTypes()

Returns the corresponding database type.

Example

package ;

import ;
import ;
import ;
import ;

import ;
import ;
import ;
import ;
import ;
import ;

/**
  * PostgreSql Inteval Fields and Mappings
  * Currently, only 1 month (30 days) intervals are supported
  * <p>
  *How to use:
  * Add on entity class
  * \@TypeDef(name="interval", typeClass = )
  * Add to field definition:
  * \@Type(type = "interval")
  * <p>
  * /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 &amp;&amp; arg1 != null &amp;&amp; (arg1) || arg0 == null &amp;&amp; arg1 == null;
 }

 public int hashCode(Object object) throws HibernateException {
  return ();
 }


 @Override
 public Object nullSafeGet(ResultSet resultSet, String[] names, SharedSessionContractImplementor sessionImplementor, Object o) throws HibernateException, SQLException {
  String interval = (names[0]);
  if (() || 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) {
   (index, );
  } else {
   //this http://postgresql.1045698./#a2175205
   Duration duration = (Duration) value;
   (index, getInterval(duration), );
  }
 }

 public static Duration getDuration(PGInterval pgInterval) {
  return (() * 24 * 3600 +
    () * 3600 +
    () * 60 +
    (int) ());
 }

 private static PGInterval getInterval(Duration value) {
  long seconds = ();
  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 = (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 ;
 }

 public int[] sqlTypes() {
  return new int[]{};
 }

}

Use custom types

At this point, we have defined our own data type. But Hibernate doesn't know how to use it yet. To do this, we need to use TypeDef annotation on Entity and use Type annotation on the attribute.

for example:

...
@Entity
@TypeDef(name = "interval", typeClass = )
public class PaperStatis implements Serializable {
...
 @Column(name = "avg_duration")
 @Type(type = "interval")
 public Duration getAvgDuration() {
  return ;
 }
...
}

Thank you for reading, I hope it can help you. Thank you for your support for this site!