PersistentObjectException: JPA 및 최대 절전 모드에서 해제된 독립된 엔티티가 지속되도록 전달됨
있다.Account
Transactions
…Transaction
있다Account
.
여기 코드 조각이 있다.
@Entity
public class Transaction {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
private Account fromAccount;
....
@Entity
public class Account {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@OneToMany(cascade = {CascadeType.ALL},fetch= FetchType.EAGER, mappedBy = "fromAccount")
private Set<Transaction> transactions;
나는 창조할 수 있다.Account
, 객체 가 및 지만 Account
옳게 반대하다그러나 기존 유지 계정을 사용하여 트랜잭션을 만들고 트랜잭션을 지속할 때 다음과 같은 예외가 표시됨:
원인: org.hibernat.PersistentObjectException: 지속할 분리된 개체: com.paulsanwald.org.hibernat.event.internal의 계정.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:141)
그래서, 나는 지속할 수 있다.Account
트랜잭션은 포함하지만 트랜잭션은 포함하지 않음Account
. 나는 이것이 그 이유라고 생각했다.Account
첨부되지 않을 수도 있지만, 이 코드는 여전히 나에게 같은 예외를 준다.
if (account.getId()!=null) {
account = entityManager.merge(account);
}
Transaction transaction = new Transaction(account,"other stuff");
// the below fails with a "detached entity" message. why?
entityManager.persist(transaction);
어떻게 하면 올바르게 저장할 수 있는 방법Transaction
, 이미 유지된 항목과 연관됨Account
물체?
해은은 하하하다를 . 단지CascadeType.MERGE
대신에CascadeType.PERSIST
또는CascadeType.ALL
.
나도 같은 문제를 겪었고CascadeType.MERGE
날 위해 일해줬어
나는 네가 정리가 되었으면 좋겠어.
이것은 전형적인 양방향 일관성 문제다.그것은 이 링크뿐만 아니라 이 링크에서도 잘 논의되고 있다.
앞의 두 링크의 기사에 따르면 양방향 관계의 양쪽에서 세터를 고정해야 한다.One side에 대한 예시 세터가 이 링크에 있다.
세터를 수정한 후 엔티티 액세스 유형을 "속성"으로 선언하고자 하는 경우."속성" 액세스 유형을 선언하는 가장 좋은 방법은 모든 주석을 구성원 속성에서 해당 게이터로 이동하는 것이다.주의의 큰 단어는 엔티티 등급 내에서 "필드"와 "속성" 접근 유형을 혼합하지 않는 경우, 그 행동이 JSR-317 규격에 의해 정의되지 않는다.
하위 엔티티에서 계단식 계단식 계단식 계단식 계단식 계단식 계단식 제거. 단지 다음과 같아야 한다.
@Entity class Transaction {
@ManyToOne // no cascading here!
private Account account;
}
(FetchType.EAGER
기본값인 만큼 제거할 수 있음@ManyToOne
)
그게 다야!
에 대해 으로써? "캐스케이드 올(Cascade ALL)"이라는 말을 통해Transaction
은 DB 한다.Account
만약 그렇다면persist(transaction)
persist(account)
또한 호출될 것이다.
그러나 일시적인 (새로운) 엔티티만 다음으로 전달될 수 있다.persist
(Transaction
이 경우).분리된 상태(또는 다른 비투과 상태)는 (또는)할 수 없다.Account
이 경우, 이미 DB에 있으므로).
따라서 "지속하기 위해 전달된 상세 도면요소"라는 예외를 받게 된다.그Account
실체는 의미가 있다!아니다Transaction
네가 불러라persist
에 관하여
당신은 일반적으로 아이에서 부모로 전파되는 것을 원하지 않는다.불행하게도 (좋은 것에서도) 많은 코드 예들이 책과 인터넷을 통해 있는데, 이 예들은 정확히 그렇게 한다.모르겠어, 왜...아마도 가끔 별 생각 없이 단순히 반복해서 베끼는 경우도 있을 것이다.
전화하면 어떻게 되는지 알아맞혀봐.remove(transaction)
아직도 그 @MonyToOne에 "Cascade ALL"이 있어?그account
(btw, 다른 모든 거래와 함께!) 또한 DB에서 삭제될 것이다.하지만 그건 네 의도가 아니었어, 그렇지?
id(pk)를 method에 전달하지 않거나 use() 대신 save() 메서드를 사용해 보십시오.
하위 연결 계단식 제거
그래서, 당신은 그 문제를 제거해야 한다.@CascadeType.ALL
처음부터@ManyToOne
한다하위 도면요소는 상위 연결로 계단식 배열해서는 안 된다.상위 엔티티만 하위 엔티티에 계단식이어야 한다.
@ManyToOne(fetch= FetchType.LAZY)
내가 설정했다는 것을 알아차려라.fetch
의 탓으로 돌리다FetchType.LAZY
왜냐하면 열성적인 집착은 공연에 매우 좋지 않기 때문이다.
연결의 양면 설정
양방향 연결이 있을 때마다 다음을 사용하여 양쪽을 동기화해야 함addChild
그리고removeChild
상위 엔티티의 메서드:
public void addTransaction(Transaction transaction) {
transcations.add(transaction);
transaction.setAccount(this);
}
public void removeTransaction(Transaction transaction) {
transcations.remove(transaction);
transaction.setAccount(null);
}
병합을 사용하는 것은 위험하고 까다롭기 때문에 당신의 경우 더러워진 해결책이다.적어도 합병할 엔티티 객체를 통과하면 거래에 대한 애착을 멈추고 대신 현재 연결된 새로운 엔티티가 반환된다는 점을 기억해야 한다.이것은 만약 누군가가 오래된 실체 사물을 여전히 소유하고 있다면, 그것에 대한 변화는 조용히 무시되고 커밋에 버려진다는 것을 의미한다.
너는 여기에 완전한 코드를 표시하지 않아서 나는 너의 거래 패턴을 다시 확인할 수 없어.이러한 상황에 도달하는 한 가지 방법은 병합을 실행할 때 트랜잭션이 활성화되지 않고 지속되는 경우입니다.이 경우 지속성 제공자는 당신이 수행하는 모든 JPA 연산에 대해 새로운 트랜잭션을 열고 호출이 돌아오기 전에 즉시 커밋하고 종료할 것으로 예상된다.만약 그렇다면, 합병은 첫 번째 거래에서 실행된 다음 합병 방법이 반환된 후에 거래가 완료되고 종료되고 반환된 실체는 이제 분리된다.그 아래 지속되는 거래는 두 번째 거래를 열 것이고, 분리되어 있는 기업을 지칭하려고 할 것이고, 예외를 줄 것이다.당신이 무엇을 하고 있는지 잘 알지 못하는 한, 항상 당신의 코드를 거래에 넣어라.
컨테이너로 관리되는 거래를 사용하면 이와 같은 모습이 될 것이다.참고: 이 방법은 세션 빈 내부에 있으며 로컬 또는 원격 인터페이스를 통해 호출된다고 가정하십시오.
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public void storeAccount(Account account) {
...
if (account.getId()!=null) {
account = entityManager.merge(account);
}
Transaction transaction = new Transaction(account,"other stuff");
entityManager.persist(account);
}
아마도 이 경우 당신은 당신의 것을 얻었을 것이다.account
병합 논리를 사용하여 개체 수 및persist
새로운 개체를 유지하기 위해 사용되며 계층에 이미 유지된 개체가 있으면 불평할 것이다.당신은 사용해야만 한다.saveOrUpdate
이런 경우에는 대신에persist
.
My Spring Data JPA 기반 답변:간단히 a를 추가했다.@Transactional
내 외부 방법에 대한 주석.
작동 이유
활성 최대 절전 모드 세션 컨텍스트가 없기 때문에 하위 엔터티가 즉시 분리되고 있었다.스프링(Data JPA) 트랜잭션을 제공하면 최대 절전 모드 세션이 존재하게 된다.
참조:
https://vladmihalcea.com/a-beginners-guide-to-jpa-hibernate-entity-state-transitions/
오래된 질문이지만, 최근에 같은 문제에 부딪혔다.여기서 내 경험을 공유하고 있어.
독립체
@Data
@Entity
@Table(name = "COURSE")
public class Course {
@Id
@GeneratedValue
private Long id;
}
도면요소 저장(JUnit)
Course course = new Course(10L, "testcourse", "DummyCourse");
testEntityManager.persist(course);
고치다
Course course = new Course(null, "testcourse", "DummyCourse");
testEntityManager.persist(course);
결론 : 엔티티 클래스에 기본 키(id)에 대한 @GeneratedValue가 있는 경우 기본 키(id)에 대한 값을 전달하지 않는지 확인하십시오.
엔티티 정의에서 다음에 대해 @JoinColumn을 지정하지 않은 경우Account
에 가입된.Transaction
이런 걸 원하게 될 거야
@Entity
public class Transaction {
@ManyToOne(cascade = {CascadeType.ALL},fetch= FetchType.EAGER)
@JoinColumn(name = "accountId", referencedColumnName = "id")
private Account fromAccount;
}
EDIT: 음, 내 생각엔 네가 그 제품을 사용한다면 유용할 것 같아.@Table
네 강의에 대한 주석을 달아라.헤. :)
아무런 도움도 되지 않고 여전히 이 예외를 받고 있는 경우, 다음 사항을 검토하십시오.equals()
방법 - 그리고 아동수집은 포함하지 않는다.특히 임베디드 컬렉션의 구조가 깊은 경우(예: A는 B, B는 C 등)
의 예에서Account -> Transactions
:
public class Account {
private Long id;
private String accountName;
private Set<Transaction> transactions;
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Account))
return false;
Account other = (Account) obj;
return Objects.equals(this.id, other.id)
&& Objects.equals(this.accountName, other.accountName)
&& Objects.equals(this.transactions, other.transactions); // <--- REMOVE THIS!
}
}
에서 transactions의 에서 를 제거equals()
표 상태가 것이 할 때마다 이는 최대 절전 모드가 오래된 개체를 업데이트하려는 것이 아니라 자식 컬렉션의 요소를 변경할 때마다 새 개체를 유지하도록 전달한다는 것을 의미하기 때문이다.
물론 이 솔루션이 모든 애플리케이션에 적합한 것은 아니며, 귀하는 다음 항목에 포함하고자 하는 것을 신중하게 설계해야 한다.equals
그리고hashCode
방법들
주석을 정확하게 선언하여 일대다 관계를 적절히 관리한다 하더라도 이 정확한 예외에 직면할 수 있다.새 하위 개체를 추가할 때Transaction
첨부된 데이터 모델에 기본 키 값을 관리해야 한다(해당되지 않는 경우).호출하기 전에 다음과 같이 선언된 하위 엔터티에 기본 키 값을 제공하는 경우persist(T)
이 예외에 직면하게 될 것이다.
@Entity
public class Transaction {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
....
이 경우 주석에서는 데이터베이스가 삽입 시 기업의 주요 키 값 생성을 관리한다고 선언하고 있다.(예: ID의 설정자를 통해) 귀하에게 제공하는 것은 이러한 예외를 야기된다.
대안으로, 그러나 실질적으로 동일한 이 주석 선언은 동일한 예외를 초래한다.
@Entity
public class Transaction {
@Id
@org.hibernate.annotations.GenericGenerator(name="system-uuid", strategy="uuid")
@GeneratedValue(generator="system-uuid")
private Long id;
....
그러니, 이 모든 것을 설정하지 마라.id
이미 관리 중인 애플리케이션 코드의 값.
어쩌면 오픈J일지도 모른다.PA 버그, 롤백 시 @Version 필드를 재설정하지만 pcVersionInit keep true.나는 @Version 필드를 선언한 AbstraceEntity를 가지고 있다.pcVersion을 재설정하여 해결할 수 있는 방법입력 필드.그러나 그것은 좋은 생각이 아니다.나는 폭포수가 지속되면 효과가 없다고 생각한다.
private static Field PC_VERSION_INIT = null;
static {
try {
PC_VERSION_INIT = AbstractEntity.class.getDeclaredField("pcVersionInit");
PC_VERSION_INIT.setAccessible(true);
} catch (NoSuchFieldException | SecurityException e) {
}
}
public T call(final EntityManager em) {
if (PC_VERSION_INIT != null && isDetached(entity)) {
try {
PC_VERSION_INIT.set(entity, false);
} catch (IllegalArgumentException | IllegalAccessException e) {
}
}
em.persist(entity);
return entity;
}
/**
* @param entity
* @param detached
* @return
*/
private boolean isDetached(final Object entity) {
if (entity instanceof PersistenceCapable) {
PersistenceCapable pc = (PersistenceCapable) entity;
if (pc.pcIsDetached() == Boolean.TRUE) {
return true;
}
}
return false;
}
모든 계정에 대해 트랜잭션을 설정해야 한다.
foreach(Account account : accounts){
account.setTransaction(transactionObj);
}
또는 ID를 많은 측면에서 null로 설정하기에 충분하다(적절한 경우).
// list of existing accounts
List<Account> accounts = new ArrayList<>(transactionObj.getAccounts());
foreach(Account account : accounts){
account.setId(null);
}
transactionObj.setAccounts(accounts);
// just persist transactionObj using EntityManager merge() method.
cascadeType.MERGE,fetch= FetchType.LAZY
@OneToMany(mapBy = "xxxx", 캐스케이드={CascadeType).MERGE, CascadeType.지속성, CascadeType.REFET}이(가) 내게 효과가 있었다.
종속 개체를 다음보다 먼저 저장하여 해결됨.
Id(자동 생성되지 않은)를 설정하지 않았기 때문에 이런 일이 내게 일어났다.그리고 관계 @MultytoOne을 사용하여 저장하려고 함
여기 내 해결책이 있다.
아래는 나의 실체다.ID에 @GeneratedValue(전략 = GenerationType)로 주석을 달도록 표시하십시오.AUTO) 즉, 최대 절전 모드에 의해 ID가 생성됨을 의미한다.엔티티 개체가 생성될 때 이 개체를 설정하지 마십시오.최대 절전 모드에서는 자동으로 생성되므로엔티티 ID 필드가 @GeneratedValue로 표시되지 않으면 ID에 값을 수동으로 할당하지 않는 것도 범죄로, IdentifierGeneration으로 간주됨을 주의하십시오.예외: 저장()을 호출하기 전에 이 클래스에 대한 ID를 수동으로 할당해야 함
@Entity
@Data
@NamedQuery(name = "SimpleObject.findAll", query="Select s FROM SimpleObject s")
public class SimpleObject {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column
private String key;
@Column
private String value;
}
그리고 여기는 나의 메인 수업이다.
public class SimpleObjectMain {
public static void main(String[] args) {
System.out.println("Hello Hello From SimpleObjectMain");
SimpleObject simpleObject = new SimpleObject();
simpleObject.setId(420L); // Not right, when id is a generated value then no need to set this.
simpleObject.setKey("Friend");
simpleObject.setValue("Bani");
EntityManager entityManager = EntityManagerUtil.getEntityManager();
entityManager.getTransaction().begin();
entityManager.persist(simpleObject);
entityManager.getTransaction().commit();
List<SimpleObject> simpleObjectList = entityManager.createNamedQuery("SimpleObject.findAll").getResultList();
for(SimpleObject simple : simpleObjectList){
System.out.println(simple);
}
entityManager.close();
}
}
내가 저걸 구하려고 했을 때, 저걸 던지는 거였어.
PersistentObjectException: detached entity passed to persist.
내가 고치기 위해 필요한 것은 simpleObject에 대한 그 ID 설정선을 메인 메소드에서 제거하는 것이었다.
내 경우 나는 지속적 방법이 사용되었을 때 거래를 하고 있었다.지속성을 변경하여 방법을 저장하자, 해결되었다.
위의 솔루션이 작동하지 않는 경우 엔티티 클래스의 getter 및 setter 메소드를 한 번만 주석 처리하고 ID 값을 설정하지 마십시오.(기본 키)그럼 이게 효과가 있을 거야.
내가 이 문제에 직면한 또 다른 이유는 트랜잭션에서 최대 절전 모드가 버전화하지 않은 엔티티가 있기 때문이다.
추가 a@Version
매핑된 모든 엔티티에 대한 주석
@Entity
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
@Version
private Integer version;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "orders")
private CustomerOrders orders;
}
@Entity
public class CustomerOrders {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private UUID id;
@Version
private Integer version;
private BigDecimal value;
}
이 오류는 JPA Lifecycle에서 발생한다.문제를 해결하기 위해, 특정한 장식가를 사용할 필요는 없다.다음과 같은 병합을 사용하여 엔티티에 가입하십시오.
entityManager.merge(transaction);
그리고 양면이 동기화되도록 게터와 세터를 올바르게 설정하는 것을 잊지 마십시오.
'programing' 카테고리의 다른 글
경로의 일부가 $route.params에 속할 때 Vuetify 버튼에서 Nuxt 링크를 정의하는 방법? (0) | 2022.04.18 |
---|---|
C에서 배열의 최대 크기는? (0) | 2022.04.18 |
Vuex-test-utils를 사용하여 구성 요소의 VueX 상태 변경을 테스트하는 방법 (0) | 2022.04.18 |
검색되지 않은 TypeError: Vue.component가 함수가 아님 (0) | 2022.04.18 |
CRC32 C 또는 C++ 구현 (0) | 2022.04.17 |