hibernate - 为 JPA/Hibernate 实现 PostgreSQL Hstore

标签 hibernate jpa hstore

我正在尝试实现 Hstore-Datatype 并在 JPA 实体中使用它。但是,当我尝试保留一些测试数据时,出现了几个错误。

为了实现 Hstore-Datatype,我使用了以下教程:Storing Sets of Key/value Pairs in a Single Db Column With Hibernate Using PostgreSQL Hstore Type

这是我现在在我的应用程序中的代码:

将 Map 转换为符合 hstore 语法的 String 的帮助器,反之亦然:

public class HstoreHelper {

    private static final String K_V_SEPARATOR = "=>";

    public static String toString(Map<String, String> m) {
        if (m.isEmpty()) {
            return "";
        }
        StringBuilder sb = new StringBuilder();
        int n = m.size();
        for (String key : m.keySet()) {
            sb.append("\"" + key + "\"" + K_V_SEPARATOR + "\"" + m.get(key) + "\"");
            if (n > 1) {
                sb.append(", ");
                n--;
            }
        }
        return sb.toString();
    }

    public static Map<String, String> toMap(String s) {
        Map<String, String> m = new HashMap<String, String>();
        if (s.isEmpty()) {
            return m;
        }
        String[] tokens = s.split(", ");
        for (String token : tokens) {
            String[] kv = token.split(K_V_SEPARATOR);
            String k = kv[0];
            k = k.trim().substring(1, k.length() - 1);
            String v = kv[1];
            v = v.trim().substring(1, v.length() - 1);
            m.put(k, v);
        }
        return m;
    }
}

一个 UserType 实现:

public class HstoreUserType implements UserType {

      public Object assemble(Serializable cached, Object owner)
              throws HibernateException {
          return cached;
      }

      public Object deepCopy(Object o) throws HibernateException {
          Map m = (Map) o;
          return new HashMap(m);
      }

      public Serializable disassemble(Object o) throws HibernateException {
          return (Serializable) o;
      }

      public boolean equals(Object o1, Object o2) throws HibernateException {
          Map m1 = (Map) o1;
          Map m2 = (Map) o2;
          return m1.equals(m2);
      }

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

      public boolean isMutable() {
          return true;
      }

      public Object nullSafeGet(ResultSet rs, String[] strings, Object o)
              throws HibernateException, SQLException {
          String col = strings[0];
          String val = rs.getString(col);
          return HstoreHelper.toMap(val);
      }

      public void nullSafeSet(PreparedStatement ps, Object obj, int i)
              throws HibernateException, SQLException {
          String s = HstoreHelper.toString((Map) obj);
          ps.setObject(i, s, Types.OTHER);
      }

      public Object replace(Object original, Object target, Object owner)
              throws HibernateException {
          return original;
      }

      public Class returnedClass() {
          return Map.class;
      }

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

并在实体 bean 中使用它:

@Entity
@TypeDef(name = "hstore", typeClass = HstoreUserType.class)
@XmlRootElement
@Table(name = "address")
public class Address {
    .
    .
    .
    @Type(type = "hstore")
    @Column(columnDefinition = "hstore")
    private Map<String, String> hs = new HashMap<String, String>();
    .
    .
    .
}

我尝试使用 address 实例发布应用程序,但出现以下错误:

14:40:47,906 INFO  [stdout] (MSC service thread 1-1) Hibernate: insert into address (housenumber, location, street, zipcode, address_id) values (?, ?, ?, ?, ?)

14:40:47,921 WARN  [com.arjuna.ats.arjuna] (MSC service thread 1-1) ARJUNA012125: TwoPhaseCoordinator.beforeCompletion - failed for SynchronizationImple< 0:ffff0a49215c:-6aa8b5cf:53b3d0e3:133, org.hibernate.engine.transaction.synchronization.internal.RegisteredSynchronization@628b66 >: java.lang.AbstractMethodError
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:155) [hibernate-core-4.0.1.Final.jar:4.0.1.Final]

14:40:48,062 INFO  [org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl] (MSC service thread 1-1) HHH000010: On release of batch it still contained JDBC statements
14:40:48,093 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-1) MSC00001: Failed to start service jboss.deployment.unit."ductbased.war".component.TestDataGenerator.START: org.jboss.msc.service.StartException in service jboss.deployment.unit."ductbased.war".component.TestDataGenerator.START: Failed to start service
at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1767) [jboss-msc-1.0.2.GA.jar:1.0.2.GA]

14:40:49,265 ERROR [org.jboss.as.server.deployment.scanner] (DeploymentScanner-threads - 2) {"JBAS014653: Composite operation failed and was rolled back. Steps that failed:" => {"Operation step-2" => {"JBAS014671: Failed services" => {"jboss.deployment.unit.\"ductbased.war\".component.TestDataGenerator.START" => "org.jboss.msc.service.StartException in service jboss.deployment.unit.\"ductbased.war\".component.TestDataGenerator.START: Failed to start service"}}}}

谁能告诉我,为什么会出现错误?本教程的作者声称,该代码适用于他,所以我有点孤单 :D 这也是我第一次实现自己的数据类型。 提前致谢!

最佳答案

对于那些在 2020 年登陆这里的人,hibernate-types 现在开箱即用地支持它。 所有积分归于 Vlad Mihalcea。复制部分代码以保留相同的代码。

https://vladmihalcea.com/map-postgresql-hstore-jpa-entity-property-hibernate/

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version>
</dependency>

在你的数据库中

CREATE EXTENSION IF NOT EXISTS hstore;
ALTER Table <Table_Name> ADD COLUMN <column_name> hstore;

在你的 POJO 中

@Entity(name = "Book")
@Table(name = "book")
@TypeDef(name = "hstore", typeClass = PostgreSQLHStoreType.class)
public class Book {
 
    @Id
    @GeneratedValue
    private Long id;
 
    @NaturalId
    @Column(length = 15)
    private String isbn;
 
    @Type(type = "hstore")
    @Column(columnDefinition = "hstore")
    private Map<String, String> properties = new HashMap<>();
 
    //Getters and setters omitted for brevity
}

示例条目

Book book = new Book();
 
book.setIsbn("978-9730228236");
book.getProperties().put("title", "High-Performance Java Persistence");
book.getProperties().put("author", "Vlad Mihalcea");
book.getProperties().put("publisher", "Amazon");
book.getProperties().put("price", "$44.95");
 
entityManager.persist(book);

关于hibernate - 为 JPA/Hibernate 实现 PostgreSQL Hstore,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24531887/

相关文章:

oracle - 在 Hibernate Criteria 中使用 ORACLE rowId

java - 使 Spring Hibernate 线程安全。最好的安慰

performance - Postgres HStore 对性能的影响是什么?

postgresql - Postgres 9.3,hstore 1.1,未知运算符 '?'

ruby-on-rails - 迁移无法识别在 schema_search_path 上创建的 hstore 扩展

java - 在线程 "main"java.lang.NoClassDefFoundError : org/hibernate/cache/spi/support/DomainDataRegionImpl中

java - 有关数据库池和 connection.setReadOnly() 方法的行为

java - 表作为枚举。是否可以?

java - 检测对绑定(bind)到(可编辑的)JTable 的实体的更新

java - 使用 Spring Boot JPA 覆盖数据源的连接池