source

휴지 상태 오류: 동일한 식별자 값을 가진 다른 개체가 세션에 이미 연결되어 있습니다.

gigabyte 2022. 11. 28. 21:10
반응형

휴지 상태 오류: 동일한 식별자 값을 가진 다른 개체가 세션에 이미 연결되어 있습니다.

기본적으로 이 구성에 몇 가지 개체가 있습니다(실제 데이터 모델은 조금 더 복잡합니다).

  • A는 B와 다대다 관계를 맺고 있다(B는inverse="true")
  • B는 C와 다대일 관계를 맺고 있다.cascade로 설정하다."save-update")
  • C는 타입/카테고리 테이블의 일종입니다.

또한 프라이머리 키는 저장 시 데이터베이스에 의해 생성된다는 점을 언급해야 합니다.

데이터에서는 A에 다른B 오브젝트 세트가 있고, 이 B 오브젝트가 같은 C 오브젝트를 참조하고 있는 문제가 발생하는 경우가 있습니다.

내가 전화했을 때session.saveOrUpdate(myAObject)휴지 상태 에러가 표시 에러가 표시됩니다."a different object with the same identifier value was already associated with the session: C"휴지 상태에서는 같은 오브젝트를 같은 세션에서 두 번 삽입/갱신/삭제할 수 없습니다만, 이 문제를 해결할 방법이 있습니까?이건 그렇게 드문 상황이 아닌 것 같아요.

이 문제를 조사하는 동안, 나는 사람들이 사용하는 것을 제안한다는 것을 보았다.session.merge()단, 이 경우 모든 "충돌하는" 객체는 공백 객체로 데이터베이스에 삽입되며 모든 값은 null로 설정됩니다.확실히 그것은 우리가 원하는 것이 아니다.

[편집] 또 하나 빠뜨린 것은 (아키텍처상의 이유로) 각 읽기 또는 쓰기는 별도의 세션에서 수행해야 한다는 것입니다.

B 오브젝트가 같은 Java C 오브젝트인스턴스를 참조하고 있지 않기 때문일 수 있습니다.데이터베이스 내의 같은 행(즉, 같은 프라이머리 키)을 참조하고 있습니다만, 다른 카피입니다.

따라서 엔티티를 관리하는 휴지 상태 세션은 동일한 기본 키를 가진 행에 대응하는 Java 개체를 추적합니다.

하나의 옵션은 같은 행을 참조하는 객체B의 엔티티가 실제로 같은 객체인스턴스 C를 참조하고 있는지 확인하는 것입니다.또는 해당 멤버 변수에 대한 캐스케이딩을 해제합니다.이렇게 하면 B가 유지되면 C는 유지되지 않습니다.C는 수동으로 따로 저장해야 합니다.C가 유형/카테고리 표라면 그렇게 하는 것이 타당할 수 있습니다.

캐스케이드를 MERGE로 설정하기만 하면 됩니다.

한 가지만 하면 돼요. 실행합니다.session_object.clear()을 사용하다그러면 세션이 클리어되고(적절한 이름으로 지정) 문제가 되는 중복 개체가 세션에서 제거됩니다.

@Hemant Kumar님 말씀에 동의합니다.감사합니다.그의 해결책에 따라 나는 내 문제를 해결했다.

예를 들어 다음과 같습니다.

@Test
public void testSavePerson() {
    try (Session session = sessionFactory.openSession()) {
        Transaction tx = session.beginTransaction();
        Person person1 = new Person();
        Person person2 = new Person();
        person1.setName("222");
        person2.setName("111");
        session.save(person1);
        session.save(person2);
        tx.commit();
    }
}

Person.java

public class Person {
    private int id;
    private String name;

    @Id
    @Column(name = "id")
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Basic
    @Column(name = "name")
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

이 코드는 항상 어플리케이션에서 실수합니다.A different object with the same identifier value was already associated with the session프라이머리 키를 자동 증가시키는 것을 잊어버린 것을 나중에 알았습니다.

이 솔루션은 프라이머리 키에 다음 코드를 추가하는 것입니다.

@GeneratedValue(strategy = GenerationType.AUTO)

즉, 테이블 내의 여러 행을 같은 오브젝트에 대한 참조로 저장하려고 합니다.

엔티티 클래스의 ID 속성을 확인합니다.

@Id
private Integer id;

로.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(unique = true, nullable = false)
private Integer id;

다음을 사용하여 휴지 상태에서 데이터베이스로 개체 ID를 할당하는 작업을 전송합니다.

<generator class="native"/>

이것으로 나는 그 문제를 해결했다.

위의 문제를 해결하는 한 가지 방법은 다음 명령을 덮어쓰는 것입니다.hashcode().
저장 전후에 휴지 상태 세션도 플러시합니다.

getHibernateTemplate().flush();

분리된 오브젝트를 명시적으로 설정하다null도움이 됩니다.

삽입할 빈에 @GeneratedValue 주석을 추가합니다.

방금 이 메시지를 받았는데 c#코드로 되어있네요.관련이 있는지는 확실하지 않습니다(단, 정확히 동일한 오류 메시지).

디버거가 중단점에 있는 동안 중단점으로 코드를 디버깅하고 개인 멤버를 통해 컬렉션을 확장했습니다.구조물을 파헤치지 않고 코드를 다시 실행하면 오류 메시지가 사라집니다.개인 소장품을 들여다보는 행위는 당시 로딩하지 말았어야 할 것들을 NHibernate가 로딩하게 만든 것 같다(개인 회원이었기 때문에).

코드 자체는 상당히 복잡한 트랜잭션에 싸여 있으며, 트랜잭션(가져오기 프로세스)의 일부로서 다수의 레코드와 종속성을 업데이트할 수 있습니다.

이 문제를 접하는 다른 사람에게도 단서가 될 수 있기를.

휴지 상태에서 "캐스케이드" 속성을 찾아 삭제하십시오."Cascade"를 사용할 수 있도록 설정하면 관련 클래스와 관련된 다른 엔티티에서 다른 작업(저장, 업데이트 및 삭제)이 호출됩니다.따라서 동일한 ID 값이 발생합니다.나한테는 효과가 있었어.

동일한 오류 메시지가 생성될 수 있는 다른 경우(커스텀)allocationSize:

@Id
@Column(name = "idpar")
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "paramsSequence")
@SequenceGenerator(name = "paramsSequence", sequenceName = "par_idpar_seq", allocationSize = 20)
private Long id;

비길 데 없이

alter sequence par_idpar_seq increment 20;

는 삽입 중에 제약조건 검증을 일으킬 수 있습니다(이것이 이해하기 쉬움).또는 "같은 식별자 값을 가진 다른 객체가 세션에 이미 관련되어 있습니다." 이 경우는 그다지 명확하지 않았습니다.

이 에러는 며칠간 발생했지만, 수정에 너무 많은 시간을 소비했습니다.

 public boolean save(OrderHeader header) {
    Session session = sessionFactory.openSession();


    Transaction transaction = session.beginTransaction();

    try {
        session.save(header);

        for (OrderDetail detail : header.getDetails()) {
            session.save(detail);
        }

        transaction.commit();
        session.close();

        return true;
    } catch (HibernateException exception) {

        exception.printStackTrace();
        transaction.rollback();
        return false;
    }
}

이 오류가 발생하기 전에는 OrderDetil 오브젝트에 ID 생성 유형을 언급하지 않았습니다.Order Details' ID를 생성하지 않으면 모든 Order Detail 객체에 대해 ID를 0으로 유지합니다.#jbx의 설명입니다.네, 이것이 가장 좋은 대답입니다.이 한 가지 예가 있습니다.

이전에 쿼리의 코드를 배치해 보십시오.이것으로 문제가 해결되었습니다.예를 들어, 이것을 변경합니다.

query1 
query2 - get the error 
update

다음과 같이 입력합니다.

query2
query1
update

제 경우 flush()만 동작하지 않았습니다.flush() 뒤에 clear()를 사용해야 했습니다.

public Object merge(final Object detachedInstance)
    {
        this.getHibernateTemplate().flush();
        this.getHibernateTemplate().clear();
        try
        {
            this.getHibernateTemplate().evict(detachedInstance);
        }
}

업데이트 쿼리를 호출하기 전에 개체의 ID를 설정하지 않았을 수 있습니다.

다음과 같은 행을 삽입하면 프라이머리 키 생성이 잘못되어 문제가 발생하였습니다.

public void addTerminal(String typeOfDevice,Map<Byte,Integer> map) {
        // TODO Auto-generated method stub
        try {
            Set<Byte> keySet = map.keySet();
            for (Byte byte1 : keySet) {
                Device device=new Device();
                device.setNumDevice(DeviceCount.map.get(byte1));
                device.setTimestamp(System.currentTimeMillis());
                device.setTypeDevice(byte1);
                this.getHibernateTemplate().save(device);
            }
            System.out.println("hah");
        }catch (Exception e) {
            // TODO: handle exception
            logger.warn("wrong");
            logger.warn(e.getStackTrace()+e.getMessage());
        }
}

ID 생성기 클래스를 ID로 변경합니다.

<id name="id" type="int">
    <column name="id" />
    <generator class="identity"  />
 </id>

EntityRepository를 사용하는 경우 저장 대신 saveAndFlush를 사용합니다.

IDE에서 hibernate를 실행하고 있는 식 탭을 열어 둔 경우, 이 예외의 원인이 되는 오브젝트에 대한 콜을 취득합니다.이 오브젝트를 삭제하려고 했습니다.또, 이 에러를 발생시키기 위해서 필요한 것 같은 삭제 콜의 브레이크 포인트가 있었습니다.다른 식 탭을 전면 탭으로 만들거나 IDE가 중단점에서 멈추지 않도록 설정을 변경하면 이 문제가 해결되었습니다.

엔티티가 매핑된 모든 엔티티에 대해 동일한 생성 유형을 가지는지 확인합니다.

예: 사용자 역할

public class UserRole extends AbstractDomain {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String longName;

private String shortName;

@Enumerated(EnumType.STRING)
private CommonStatus status;

private String roleCode;

private Long level;

@Column(columnDefinition = "integer default 0")
private Integer subRoleCount;

private String modification;

@ManyToOne(fetch = FetchType.LAZY)
private TypeOfUsers licenseType;

}

모듈:

public class Modules implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String longName;

private String shortName;

}

매핑이 있는 메인엔티티

public class RoleModules implements Serializable{

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private UserRole role;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private Modules modules;

@Type(type = "yes_no")
private boolean isPrimaryModule;

public boolean getIsPrimaryModule() {
    return isPrimaryModule;
}

}

In addition to all the previous answers, a possible fix to this problem in a large scale project, if your using a Value Object for your classes don't set the id attribute in the VO Transformer class.

The reason for this issue is you have have different copies of objects referring into same raw in your child table, so spring trying to treat your object as new object but while saving it identifies there is a raw with same primary key. So it gives above error.

Best solution for this issue is to load the whole object (parent entity with child entities) from DB (you already know the primary key of parent object), then update values in the object loaded from DB from your new object(which you were trying to save) and then save the object you loaded from the DB which has new values.

This will update your values in the DB without giving above error.

PS- Do not need to update ids as they already exist in object loaded from DB, update only the values need to be changed

Another way to solve this if you are using spring data:

  • 콜을 교환하다entityManager.persist()에의 호출로repository.save(),그리고.
  • 콜을 교환하다entityManager.query().getResultList()에의 문의가 있는 경우 등repository.findBy...

This way, spring data keeps track of the objects. It enables multiple get and persist calls.

instead of just @Id try @Id @GeneratedValue(strategy = GenerationType.AUTO) it worked for me

In my case, I had OneToOne relationship and after saving one row with a foreign key, attempt to save another row with the same foreign key throw the same exception. It means that requirement was not OneToOne relationship, but should be ManyToOne. So I have changed it to ManyToOne and it started working.

This error commonly occurs because you are violating a column of unique type or primary key when trying to insert repeated data.

make sure primary key is different for every entity.

primary key must be unique

just commit current transaction.

currentSession.getTransaction().commit();

now you can begin another Transaction and do anything on entity

ReferenceURL : https://stackoverflow.com/questions/16246675/hibernate-error-a-different-object-with-the-same-identifier-value-was-already-a

반응형