【问题标题】:HibernateException: identifier of an instance was altered from Alert@62794582 to Alert@c82ad22HibernateException:实例的标识符已从 Alert@62794582 更改为 Alert@c82ad22
【发布时间】:2018-09-18 03:10:13
【问题描述】:

我正在使用 Hibernate JPA 实现持久性 API。
我正在使用 PostgreSQL 10.4 并将数据存储为 JSONB。
我正在分享我对 Hibernate 和 Entity 的实现,请指出为什么我会遇到异常。

我按照这篇精彩的文章来实现自定义 UserType 因为 Hibernate 不支持 PostgreSQL JSONB 数据类型:
https://www.thoughts-on-java.org/persist-postgresqls-jsonb-data-type-hibernate/

我能够创建实体映射并执行简单的选择查询并打印分配给映射的值。

问题是当我对事务执行提交操作时,出现以下异常:

22:42:35.218 [主要] 调试 org.hibernate.engine.transaction.internal.TransactionImpl - 回滚() 在线程“main”中调用非活动事务异常 javax.persistence.RollbackException:提交时出错 交易于 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:86) 在 com.postgres.main.TestMain.main(TestMain.java:41) 引起: javax.persistence.PersistenceException: org.hibernate.HibernateException: 实例的标识符 com.postgres.model.Alert 从 com.postgres.model.Alert@62794582 到 com.postgres.model.Alert@c82ad22 在 org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692) 在 org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602) 在 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:67) ... 1 更多原因:org.hibernate.HibernateException:标识符 com.postgres.model.Alert 的一个实例从 com.postgres.model.Alert@62794582 到 com.postgres.model.Alert@c82ad22 在 org.hibernate.event.internal.DefaultFlushEntityEventListener.checkId(DefaultFlushEntityEventListener.java:64) 在 org.hibernate.event.internal.DefaultFlushEntityEventListener.getValues(DefaultFlushEntityEventListener.java:175) 在 org.hibernate.event.internal.DefaultFlushEntityEventListener.onFlushEntity(DefaultFlushEntityEventListener.java:135) 在 org.hibernate.event.internal.AbstractFlushingEventListener.flushEntities(AbstractFlushingEventListener.java:216) 在 org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:85) 在 org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:38) 在 org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1295) 在 org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:468) 在 org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3135) 在 org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2352) 在 org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:485) 在 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:147) 在 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$100(JdbcResourceLocalTransactionCoordinatorImpl.java:38) 在 org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:231) 在 org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:65) 在 org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:61) ... 1 更多

我还关注了以下帖子,人们分享了他们如何解决此问题,但这对我没有帮助:
Hibernate: How to fix "identifier of an instance altered from X to Y"?

这是警报实体:

@Entity
@IdClass(Alert.class)
@Table(name = "alert")
public class Alert implements Serializable
{
    private static final long serialVersionUID = 1L;

    @Id
    @Column(name = "historyid")
    private Character historyId;

    @Id
    @Column(name = "tenantname")
    private Character tenantName;

    @Column(name = "data")
    @Type(type = "AlertJsonUserType")
    private AlertJson alertJson;

    public Character getHistoryId() {
        return historyId;
    }

    public void setHistoryId(Character historyId) {
        this.historyId = historyId;
    }

    public Character getTenantName() {
        return tenantName;
    }

    public void setTenantName(Character tenantName) {
        this.tenantName = tenantName;
    }

    public AlertJson getAlertJson() {
        return alertJson;
    }

    public void setAlertJson(AlertJson alertJson) {
        this.alertJson = alertJson;
    }
}


这是警报实体中 JSONB 元素的实体

public class AlertJson implements Serializable 
{
    private static final long serialVersionUID = 1L;

    @JsonProperty("DeviceId")
    private String deviceId;

    @JsonProperty("TenantName")
    private String tenantName;

    @JsonProperty("FocusPointId")
    private List<FocusPointId> focusPointId;

    public String getDeviceId() {
        return deviceId;
    }

    public void setDeviceId(String deviceId) {
        this.deviceId = deviceId;
    }

    public String getTenantName() {
        return tenantName;
    }

    public void setTenantName(String tenantName) {
        this.tenantName = tenantName;
    }

    public List<FocusPointId> getFocusPointId() {
        return focusPointId;
    }

    public void setFocusPointId(List<FocusPointId> focusPointId) {
        this.focusPointId = focusPointId;
    }
}

class FocusPointId
{
    @JsonProperty("PartNumber")
    private String partNumber;

    @JsonProperty("SerialNumber")
    private String serialNumber;

    public String getPartNumber() {
        return partNumber;
    }

    public void setPartNumber(String partNumber) {
        this.partNumber = partNumber;
    }

    public String getSerialNumber() {
        return serialNumber;
    }

    public void setSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
    }
  }


下面是 main() 的 sn-p,我在其中创建 EntityManager 实例并发出查询

public static void main(String[] args)
{
    EntityManagerFactory emf = Persistence.createEntityManagerFactory("my-persistence-unit");

    EntityManager em = emf.createEntityManager();
    em.getTransaction().begin();

    Query alertQuery = em.createNativeQuery("SELECT * FROM \"A.01\".\"Alert\" where tenantname = 'TestUser-152'", Alert.class);
    List<Alert> alertList = alertQuery.getResultList();

    for(Alert jsonElement : alertList)
    {
        System.out.println("======> "+"Device: " + jsonElement.getAlertJson().getDeviceId() + " TenantName: " +jsonElement.getAlertJson().getTenantName());
    }

    em.getTransaction().commit();

    emf.close();
}

下面是描述表和约束。 PK 既是 historyid 也是租户名。

【问题讨论】:

  • 似乎您在代码中的某处重新分配了 id,因此休眠拒绝了这个新的 Id 更新。尝试调试你的代码并观察 id 的变化。

标签: postgresql hibernate jpa jsonb usertype


【解决方案1】:

我认为你有这个问题是因为你错误地使用了 IdClass 注释,你应该创建一个单独的类 AlertId 例如,它必须来自你组合的 PK 的字段,并且这个类应该用作 @987654324 的参数@注解

【讨论】:

  • 谢谢你,这有帮助。它修复了早期的问题,但我得到了新的异常。
  • 此问题已解决,谢谢。根据您的输入,我按照这篇文章处理了 JPA 中的两个复合键并且它起作用了:vladmihalcea.com/…
最近更新 更多