최대 절전 모드 오류 : org.hibernate.NonUniqueObjectException : 동일한 식별자 값을 가진 다른 개체가 이미 세션과 연결되었습니다. was already associated

두 개의 사용자 개체가 있고 사용하여 개체를 저장하려고하는 동안

session.save(userObj);

다음과 같은 오류가 발생합니다.

Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:
[com.pojo.rtrequests.User#com.pojo.rtrequests.User@d079b40b]

나는 사용하여 세션을 만들고 있습니다

BaseHibernateDAO dao = new BaseHibernateDAO();          

rtsession = dao.getSession(userData.getRegion(),
                           BaseHibernateDAO.RTREQUESTS_DATABASE_NAME);

rttrans = rtsession.beginTransaction();
rttrans.begin();

rtsession.save(userObj1);
rtsession.save(userObj2);

rtsession.flush();
rttrans.commit();

rtsession.close(); // in finally block

나는 또한 session.clear()저장하기 전에 시도했지만 여전히 운이 없습니다.

이것은 사용자 요청이 올 때 처음으로 세션 개체를 얻는 것이므로 개체가 세션에 존재한다고 말하는 이유를 얻고 있습니다.

어떤 제안?



답변

이 오류가 여러 번 발생했으며 추적하기가 매우 어려울 수 있습니다.

기본적으로 hibernate가 말하는 것은 동일한 식별자 (동일한 기본 키)를 가진 두 개의 개체가 있지만 동일한 개체가 아니라는 것입니다.

나는 당신이 당신의 코드를 쪼개는 것을 제안 할 것이다. 즉, 오류가 사라질 때까지 비트를 주석으로 처리 한 다음 코드가 돌아올 때까지 코드를 다시 넣으면 오류를 찾을 수있다.

대부분의 경우 개체 A와 B 사이에 연속 저장이 있지만 개체 B가 이미 세션과 연결되어 있지만 A에있는 것과 동일한 B 인스턴스에 있지 않은 경우 연속 저장을 통해 발생합니다.

어떤 기본 키 생성기를 사용하고 있습니까?

내가 묻는 이유는이 오류가 객체의 지속 상태 (즉, 객체가 지속되는지 여부)를 확인하기 위해 최대 절전 모드에 지시하는 방법과 관련이 있기 때문입니다. 최대 절전 모드가 이미 영구적 인 개체를 유지하려고하기 때문에 오류가 발생할 수 있습니다. 실제로 save hibernate를 사용하면 해당 객체를 시도하고 유지하며 세션과 관련된 동일한 기본 키를 가진 객체가 이미있을 수 있습니다.

기본 키 조합 (열 1 및 열 2)을 기반으로 행이 10 개인 테이블에 대해 최대 절전 모드 클래스 개체가 있다고 가정합니다. 이제 특정 시점에 테이블에서 5 개의 행을 제거했습니다. 이제 동일한 10 개의 행을 다시 추가하려고 시도하는 동안 hibernate가 데이터베이스에서 개체를 유지하려고 시도하면 이미 제거 된 5 개의 행이 오류없이 추가됩니다. 이제 이미 존재하는 나머지 5 개 행은이 예외를 발생시킵니다.

따라서 쉬운 접근 방식은 무언가의 일부인 테이블에서 값을 업데이트 / 제거했는지 확인하고 나중에 동일한 객체를 다시 삽입하려고 시도하는지 확인하는 것입니다.


답변

이것은 최대 절전 모드가 해결하는 것보다 더 많은 문제를 일으키는 유일한 지점입니다. 제 경우에는 동일한 식별자 0을 가진 많은 객체가 있습니다. 왜냐하면 새롭고 하나도 없기 때문입니다. db가 생성합니다. 어딘가에 0 신호 Id가 설정되지 않았다는 것을 읽었습니다. 그것들을 지속시키는 직관적 인 방법은 그것들을 반복하고 객체를 저장하기 위해 최대 절전 모드라고 말하는 것입니다. 하지만 그렇게 할 수는 없습니다. “물론 최대 절전 모드가 이런 식으로 작동한다는 것을 알아야합니다. 따라서해야합니다.”그래서 이제 Ids를 long 대신 Long으로 변경하여 작동하는지 살펴볼 수 있습니다. 결국에는 최대 절전 모드가 추가 불투명 부담 일 뿐이므로 간단한 매퍼로 직접 수행하는 것이 더 쉽습니다. 또 다른 예 : 한 데이터베이스에서 매개 변수를 읽고 다른 데이터베이스에 유지하려고하면 거의 모든 작업을 수동으로해야합니다.


답변

USe method session.evict(object);의 기능은 evict()세션 캐시에서 인스턴스를 제거하는 데 사용됩니다. 따라서 처음으로 객체를 저장 session.save(object)하려면 캐시에서 객체를 제거하기 전에 메서드를 호출 하여 객체를 저장하십시오. 같은 방법으로 evict ()를 호출 session.saveOrUpdate(object)하거나 session.update(object)호출하기 전에 객체를 업데이트합니다 .


답변

이것은 읽기 및 쓰기에 동일한 세션 개체를 사용했을 때 발생할 수 있습니다. 어떻게? 하나의 세션을 생성했다고 가정합니다. 기본 키 Emp_id = 101로 직원 테이블에서 레코드를 읽었습니다. 이제 Java에서 레코드를 수정했습니다. 그리고 Employee 레코드를 데이터베이스에 저장합니다. 우리는 여기서 세션을 닫지 않았습니다. 읽은 개체도 세션에 유지됩니다. 우리가 작성하고자하는 객체와 충돌합니다. 따라서이 오류가 발생합니다.


답변

누군가가 이미 위에서 지적했듯이 나는 관계 cascade=all의 양쪽 끝에 있을 때이 문제에 부딪 혔 one-to-many으므로 A-> B (A에서 일대 다, B에서 다 대일)를 가정하고 A에서 B를 호출 한 다음 saveOrUpdate (A)를 호출하면 순환 저장 요청이 발생했습니다. 즉, A의 저장은 A의 저장을 트리거하는 B의 저장을 트리거하고 세 번째 인스턴스에서는 엔티티 (A의)가 시도되었습니다. sessionPersistenceContext에 duplicateObject 예외가 발생했습니다.
  한쪽 끝에서 캐스케이드를 제거하여 해결할 수 있습니다.


답변

session.merge(obj)동일한 식별자 영구 객체로 다른 세션으로 저장하는 경우를 사용할 수 있습니다 .
효과가 있었고 이전에도 같은 문제가있었습니다.


답변

나는 또한이 문제에 부딪 쳤고 오류를 찾기가 어려웠습니다.

내가 가진 문제는 다음과 같습니다.

다른 최대 절전 세션을 사용하여 Dao가 객체를 읽었습니다.

이 예외를 방지하려면 나중에이 개체를 저장 / 업데이트 할 dao로 개체를 다시 읽으십시오.

그래서:

class A{

 readFoo(){
       someDaoA.read(myBadAssObject); //Different Session than in class B
    }

}

class B{



 saveFoo(){
       someDaoB.read(myBadAssObjectAgain); //Different Session than in class A
       [...]
       myBadAssObjectAgain.fooValue = 'bar';
       persist();
    }

}

어떤 사람들은 많은 시간을 절약 할 수 있기를 바랍니다!