Hibernate: Как исправить «идентификатор экземпляра, измененного с X на Y»? - PullRequest
51 голосов
/ 14 ноября 2010
org.hibernate.HibernateException: identifier of an instance 
of org.cometd.hibernate.User altered from 12 to 3

фактически, моя таблица user действительно должна динамически менять свое значение, мое Java-приложение является многопоточным. Есть идеи как это исправить?

Ответы [ 15 ]

37 голосов
/ 14 ноября 2010

Вы меняете значение первичного ключа объекта User где-нибудь?Ты не должен этого делать.Проверьте правильность сопоставления первичного ключа.

Как выглядит файл сопоставления XML или примечания сопоставления?

26 голосов
/ 15 февраля 2011

Вы должны отсоединить свою сущность от сеанса, прежде чем изменять ее поля идентификатора.

16 голосов
/ 12 июля 2012

В моем случае поле PK в hbm.xml имело тип "integer", но в коде компонента оно было long.

4 голосов
/ 30 ноября 2014

В моем случае имена получателей и сеттеров отличались от имени переменной.

private Long stockId;
    public Long getStockID() {
        return stockId;
    }
    public void setStockID(Long stockID) {
        this.stockId = stockID;
    }

где это должно быть

public Long getStockId() {
    return stockId;
}
public void setStockId(Long stockID) {
    this.stockId = stockID;
}
4 голосов
/ 17 декабря 2013

В моем случае я решил это, изменив тип поля @Id с long на Long.

3 голосов
/ 12 января 2015

Убедитесь, что вы не пытаетесь использовать один и тот же объект User более одного раза при изменении идентификатора.Другими словами, если вы что-то делали в операции пакетного типа:

User user = new User();  // Using the same one over and over, won't work
List<Customer> customers = fetchCustomersFromSomeService();
for(Customer customer : customers) {
 // User user = new User(); <-- This would work, you get a new one each time
 user.setId(customer.getId());
 user.setName(customer.getName());
 saveUserToDB(user);
}
3 голосов
/ 06 января 2014

В моем случае шаблон имел опечатку, поэтому вместо проверки на эквивалентность (==) он использовал присвоение, равное (=).

Итак, я изменил логику шаблона с:

if (user1.id = user2.id) ...

до

if (user1.id == user2.id) ...

и теперь все хорошо. Итак, проверьте свои взгляды!

3 голосов
/ 05 декабря 2011

В моем конкретном случае это было вызвано методом в моей реализации сервиса, который нуждался в аннотации @Transactional(readOnly = true) пружины. Как только я добавил это, проблема была решена. Необычно, однако, это было только утверждение выбора.

2 голосов
/ 23 июня 2015

Я тоже столкнулся с этой проблемой.

Целевая таблица - это таблица отношений, связывающая два идентификатора из разных таблиц. У меня есть УНИКАЛЬНОЕ ограничение на комбинацию значений, заменяющее PK. При обновлении одного из значений кортежа произошла эта ошибка.

Вот так выглядит таблица (MySQL):

CREATE TABLE my_relation_table (
  mrt_left_id BIGINT NOT NULL,
  mrt_right_id BIGINT NOT NULL,
  UNIQUE KEY uix_my_relation_table (mrt_left_id, mrt_right_id),
  FOREIGN KEY (mrt_left_id)
    REFERENCES left_table(lef_id),
  FOREIGN KEY (mrt_right_id)
    REFERENCES right_table(rig_id)
);

Класс Entity для объекта RelationWithUnique выглядит в основном так:

@Entity
@IdClass(RelationWithUnique.class)
@Table(name = "my_relation_table")
public class RelationWithUnique implements Serializable {

  ...

  @Id
  @ManyToOne
  @JoinColumn(name = "mrt_left_id", referencedColumnName = "left_table.lef_id")
  private LeftTableEntity leftId;

  @Id
  @ManyToOne
  @JoinColumn(name = "mrt_right_id", referencedColumnName = "right_table.rig_id")
  private RightTableEntity rightId;

  ...

Я исправил это

// usually, we need to detach the object as we are updating the PK
// (rightId being part of the UNIQUE constraint) => PK
// but this would produce a duplicate entry, 
// therefore, we simply delete the old tuple and add the new one
final RelationWithUnique newRelation = new RelationWithUnique();
newRelation.setLeftId(oldRelation.getLeftId());
newRelation.setRightId(rightId);  // here, the value is updated actually
entityManager.remove(oldRelation);
entityManager.persist(newRelation);

Большое спасибо за подсказку ПК, я просто пропустил это.

1 голос
/ 23 ноября 2016

Проблема также может быть в различных типах объектов объекта («Пользователь» в вашем случае) и типа, который вы просите hibernate, чтобы получить session.get(type, id);.

В моем случае ошибка была identifier of an instance of <skipped> was altered from 16 to 32. Тип объекта PK был Integer, для спящего режима был задан тип Long.

...