최대 절전 모드를 사용하여 개체를 저장할 때 다음 오류가 발생합니다.
object references an unsaved transient instance - save the transient instance before flushing
최대 절전 모드를 사용하여 개체를 저장할 때 다음 오류가 발생합니다.
object references an unsaved transient instance - save the transient instance before flushing
답변:
컬렉션 매핑에 ( cascade="all"
xml을 사용하는 경우) 또는 cascade=CascadeType.ALL
(주석을 사용하는 경우 ) 포함해야 합니다.
이것은 엔티티에 콜렉션이 있고 해당 콜렉션에 데이터베이스에없는 하나 이상의 항목이 있기 때문에 발생합니다. 위의 옵션을 지정하면 부모를 저장할 때 데이터베이스에 저장하도록 최대 절전 모드를 설정합니다.
나는 이것이 반복되는 대답 일 것이라고 생각하지만, 명확히하기 위해 @OneToOne
매핑뿐만 아니라을 얻었 습니다 @OneToMany
. 두 경우 모두 Child
내가 추가 한 객체 Parent
가 데이터베이스에 아직 저장되지 않았다는 사실입니다 . 나는를 추가 할 때 그래서 Child
받는 Parent
후 저장 Parent
, Hibernate는 던져 것 "object references an unsaved transient instance - save the transient instance before flushing"
부모를 저장할 때 메시지.
두 경우 모두 문제를 해결 하기 cascade = {CascadeType.ALL}
위해 Parent's
참조를 추가 Child
하면 문제가 해결됩니다. 이것은 구원 Child
과를 Parent
.
반복되는 답변에 대해 죄송합니다. 사람들을 위해 더 명확하게 설명하고 싶었습니다.
@OneToOne(cascade = {CascadeType.ALL})
@JoinColumn(name = "performancelog_id")
public PerformanceLog getPerformanceLog() {
return performanceLog;
}
new MyEntity
데이터베이스에서 동기화 된 인스턴스를 가져 오는 대신 엔티티 객체를 데이터베이스 와 동기화하지 않고 플러시하지 않고 생성 했습니다. 해당 인스턴스를 사용하여 최대 절전 모드 쿼리를 수행하면 데이터베이스에있을 것으로 예상되는 것과 앱의 메모리에있는 것이 다르다는 것을 알 수 있습니다. 이 경우-단순히 엔티티를 DB에서 동기화 / 가져 와서 사용하십시오. CascadeType.ALL이 필요하지 않습니다.
이것은 Hibernate가 당신이 저장하고있는 객체와 관련된 객체를 저장해야한다고 생각할 때 객체를 저장할 때 발생합니다.
나는이 문제가 있었고 참조 된 객체의 변경 사항을 저장하고 싶지 않아서 캐스케이드 유형이 없음을 원했습니다.
요령은 Hibernate가 참조 된 오브젝트가 저장이 필요한 새로운 오브젝트라고 생각하지 않도록 참조 된 오브젝트의 ID와 VERSION이 설정되도록하는 것이다. 이것은 나를 위해 일했습니다.
저장하는 클래스의 모든 관계를 살펴보고 연관된 오브젝트 (및 연관된 오브젝트의 연관된 오브젝트)를 해결하고 오브젝트 트리의 모든 오브젝트에 ID 및 VERSION이 설정되어 있는지 확인하십시오.
JPA 및 Hibernate를 사용할 때이 기사 에서 설명했듯이 엔티티는 다음 4 가지 상태 중 하나 일 수 있습니다.
새로 만들기 -최대 절전 모드 세션 (일명 지속성 컨텍스트)과 연결되지 않았으며 데이터베이스 테이블 행에 매핑되지 않은 새로 생성 된 개체는 새로 만들기 또는 임시 상태 인 것으로 간주됩니다.
지속 되려면 persist
메소드 를 명시 적으로 호출 하거나 전이 지속 메커니즘을 사용해야합니다.
지속적 -지속적 엔티티가 데이터베이스 테이블 행과 연관되었으며 현재 실행중인 지속성 컨텍스트에 의해 관리되고 있습니다.
이러한 엔티티에 대한 모든 변경 사항은 감지되어 데이터베이스로 전파됩니다 (세션 플러시 시간 동안).
분리됨 -현재 실행중인 지속성 컨텍스트가 닫히면 이전에 관리 된 모든 엔티티가 분리됩니다. 연속적인 변경 사항은 더 이상 추적되지 않으며 자동 데이터베이스 동기화가 수행되지 않습니다.
제거됨 -JPA에서는 관리 대상 엔티티 만 제거하도록 요구하지만 Hibernate는 분리 된 엔티티를 삭제할 수도 있습니다 (단, remove
메소드 호출을 통해서만 ).
다른 한 상태에서 개체를 이동하려면, 당신은 사용할 수 있습니다 persist
, remove
또는 merge
방법.
질문에서 설명하는 문제 :
object references an unsaved transient instance - save the transient instance before flushing
New 상태의 엔터티를 Managed 상태 인 엔터티에 연결하면 발생합니다 .
자식 엔터티를 부모 엔터티의 일대 다 컬렉션에 연결하고 컬렉션이 cascade
엔터티 상태 전환 이 아닌 경우에 발생할 수 있습니다 .
따라서이 기사 에서 설명했듯이 다음과 같이이 실패를 트리거 한 엔티티 연관에 계단식을 추가하여이 문제를 해결할 수 있습니다.
@OneToOne
협회@OneToOne(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private PostDetails details;
속성에
CascadeType.ALL
추가 한 값을 확인하십시오cascade
.
@OneToMany
협회@OneToMany(
mappedBy = "post",
orphanRemoval = true,
cascade = CascadeType.ALL)
private List<Comment> comments = new ArrayList<>();
또한, 양방향 연관에 CascadeType.ALL
적합합니다 .@OneToMany
이제 계단식 배열이 양방향으로 제대로 작동하려면 부모 및 자식 연결이 동기화되어 있는지 확인해야합니다.
이 목표를 달성하는 가장 좋은 방법에 대한 자세한 내용은 이 기사 를 확인하십시오 .
@ManyToMany
협회@ManyToMany(
mappedBy = "authors",
cascade = {
CascadeType.PERSIST,
CascadeType.MERGE
}
)
private List<Book> books = new ArrayList<>();
@ManyToMany
연관 에서는 CascadeType.ALL
또는 orphanRemoval
하나의 상위 엔티티에서 다른 상위 엔티티로 엔티티 삭제 상태 전이를 전파하므로 또는 사용할 수 없습니다 .
따라서 @ManyToMany
연결의 경우 일반적으로 CascadeType.PERSIST
또는 CascadeType.MERGE
작업을 계단식으로 연결 합니다. 또는이를 DETACH
또는로 확장 할 수 있습니다 REFRESH
.
@ManyToMany
연결 을 매핑하는 가장 좋은 방법에 대한 자세한 내용은 이 기사 도 확인하십시오 .
또는 최소한의 "파워"를 사용하려면 (예 : 계단식 삭제를 원하지 않는 경우) 원하는 것을 달성하십시오.
import org.hibernate.annotations.Cascade;
import org.hibernate.annotations.CascadeType;
...
@Cascade({CascadeType.SAVE_UPDATE})
private Set<Child> children;
@ManyToMany(cascade={PERSIST, MERGE, REFRESH, DETACH})
(모두 제거 제외)는 최대 절전 모드처럼 업데이트를 캐스케이드 CascadeType.SAVE_UPDATE
하지 않습니다.
제 경우이를 구비하지 기인 된 CascadeType
온 @ManyToOne
쌍방향 관계의 측면. 더 정확히 말하면, 나는했다 CascadeType.ALL
에 @OneToMany
측면과 그것을하지 않았다 @ManyToOne
. 추가 CascadeType.ALL
하여 @ManyToOne
문제 를 해결했습니다.
일대 다 측면 :
@OneToMany(cascade = CascadeType.ALL, mappedBy="globalConfig", orphanRemoval = true)
private Set<GlobalConfigScope>gcScopeSet;
다대 일면 (문제를 일으켰다)
@ManyToOne
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
다 대일 (을 추가하여 수정 CascadeType.PERSIST
)
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name="global_config_id")
private GlobalConfig globalConfig;
이것은 데이터베이스의 기존 레코드에 @Version으로 주석이 달린 필드에 대한 NULL 값이있는 엔티티를 유지할 때 발생했습니다 (낙관적 잠금). 데이터베이스에서 NULL 값을 0으로 업데이트하면이 문제가 해결되었습니다.
이것이 오류의 유일한 이유는 아닙니다. 코딩에서 오타 오류가 발생하여 이미 저장된 엔터티의 값을 설정했다고 생각합니다.
X x2 = new X();
x.setXid(memberid); // Error happened here - x was a previous global entity I created earlier
Y.setX(x2);
오류를 일으킨 변수를 정확히 찾아서 오류를 발견했습니다 (이 경우 String xid
). catch
엔터티를 저장하고 추적을 인쇄하는 전체 코드 블록 주위를 사용했습니다 .
{
code block that performed the operation
} catch (Exception e) {
e.printStackTrace(); // put a break-point here and inspect the 'e'
return ERROR;
}
Cascade.All
정말로 필요할 때까지 사용하지 마십시오 . Role
및 Permission
양방향이 manyToMany
관계를. 그런 다음 다음 코드가 정상적으로 작동합니다.
Permission p = new Permission();
p.setName("help");
Permission p2 = new Permission();
p2.setName("self_info");
p = (Permission)crudRepository.save(p); // returned p has id filled in.
p2 = (Permission)crudRepository.save(p2); // so does p2.
Role role = new Role();
role.setAvailable(true);
role.setDescription("a test role");
role.setRole("admin");
List<Permission> pList = new ArrayList<Permission>();
pList.add(p);
pList.add(p2);
role.setPermissions(pList);
crudRepository.save(role);
객체가 "새"객체 인 경우 동일한 오류가 발생합니다.
내 2 센트를 추가하기 위해 실수 null
로 ID 로 보낼 때도 동일한 문제가 발생했습니다 . 아래 코드는 내 시나리오를 보여줍니다 (그리고 OP는 특정 시나리오를 언급하지 않았습니다) .
Employee emp = new Employee();
emp.setDept(new Dept(deptId)); // --> when deptId PKID is null, same error will be thrown
// calls to other setters...
em.persist(emp);
여기서는 다른 선택 쿼리를 실행하고 싶지 않기 때문에 실제로 부서 엔티티를 먼저 가져 오지 않고 기존 부서 ID를 새 직원 인스턴스로 설정합니다.
일부 시나리오에서 deptId
PKID는null
호출 메소드에서 오는 것이며 동일한 오류가 발생합니다.
따라서 null
PK ID 값을 확인하십시오
이 문제는로 표시된 메소드에서 새 엔터티 및 관련 엔터티를 만든 @Transactional
다음 저장하기 전에 쿼리를 수행 할 때 발생했습니다. 전의
@Transactional
public someService() {
Entity someEntity = new Entity();
AssocaiatedEntity associatedEntity = new AssocaitedEntity();
someEntity.setAssociatedEntity(associatedEntity);
associatedEntity.setEntity(someEntity);
// Performing any query was causing hibernate to attempt to persist the new entity. It would then throw an exception
someDao.getSomething();
entityDao.create(someEntity);
}
수정하기 위해 새 엔터티를 만들기 전에 쿼리를 수행했습니다.
나는 또한 같은 상황에 직면했다. 속성 위에 다음 주석을 설정하면 예외 프롬프트가 해결되었습니다.
내가 직면 한 예외.
Exception in thread "main" java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: com.model.Car_OneToMany
극복하기 위해 내가 사용한 주석.
@OneToMany(cascade = {CascadeType.ALL})
@Column(name = "ListOfCarsDrivenByDriver")
private List<Car_OneToMany> listOfCarsBeingDriven = new ArrayList<Car_OneToMany>();
Hibernate가 예외를 던지게 한 이유 :
부모 개체에 연결 한 자식 개체가 그 순간 데이터베이스에 없기 때문에 콘솔에서이 예외가 발생합니다.
를 제공함으로써 @OneToMany(cascade = {CascadeType.ALL})
, 그것은 Hibernate에게 부모 객체를 저장하는 동안 그것들을 데이터베이스에 저장하도록 지시한다.
또 다른 가능한 이유는 다음과 같습니다. 제 경우에는 부모를 저장하기 전에 자녀를 새로운 엔티티에 저장하려고했습니다.
코드는 User.java 모델에서 다음과 같습니다.
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.setNewPassword(password);
this.timeJoin = new Date();
create();
setNewPassword () 메소드는 PasswordHistory 레코드를 작성하고이를 사용자의 히스토리 콜렉션에 추가합니다. 부모에 대해 create () 문이 아직 실행되지 않았으므로 아직 생성되지 않은 엔터티 컬렉션에 저장하려고했습니다. create () 호출 후 setNewPassword () 호출을 이동하는 것이 문제를 해결하기 위해해야했습니다.
this.lastName = lastName;
this.isAdmin = isAdmin;
this.accountStatus = "Active";
this.timeJoin = new Date();
create();
this.setNewPassword(password);
아직 지속되지 않은 다른 객체에 대한 참조가있는 객체를 유지하려고했기 때문에 존재하지 않는 행에 대한 참조를 "DB 측"에서 시도하기 때문입니다.
이 문제를 해결하는 간단한 방법은 두 엔티티를 모두 저장하는 것입니다. 먼저 하위 항목을 저장 한 다음 상위 항목을 저장하십시오. 부모 엔터티는 외래 키 값의 자식 엔터티에 의존하기 때문입니다.
일대일 관계에 대한 간단한 시험 아래
insert into Department (name, numOfemp, Depno) values (?, ?, ?)
Hibernate: insert into Employee (SSN, dep_Depno, firstName, lastName, middleName, empno) values (?, ?, ?, ?, ?, ?)
Session session=sf.openSession();
session.beginTransaction();
session.save(dep);
session.save(emp);
오류의 가능한 원인 중 하나는 상위 실체 값의 설정이 존재하지 않기 때문이다. 예를 들어 부서-직원 관계의 경우 오류를 해결하려면 이것을 작성해야합니다.
Department dept = (Department)session.load(Department.class, dept_code); // dept_code is from the jsp form which you get in the controller with @RequestParam String department
employee.setDepartment(dept);
이 오류의 가능성은 너무 많으며 일부 다른 가능성은 페이지 추가 또는 페이지 편집에도 있습니다. 제 경우에는 AdvanceSalary 객체를 저장하려고했습니다. 문제는 편집시 AdvanceSalary employee.employee_id가 null이라는 것입니다. 편집시 나는 employee.employee_id를 설정하지 않았기 때문에. 숨겨진 필드를 만들어서 설정했습니다. 내 코드는 절대적으로 잘 작동합니다.
@Entity(name = "ic_advance_salary")
@Table(name = "ic_advance_salary")
public class AdvanceSalary extends BaseDO{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "employee_id", nullable = false)
private Employee employee;
@Column(name = "employee_id", insertable=false, updatable=false)
@NotNull(message="Please enter employee Id")
private Long employee_id;
@Column(name = "advance_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
@NotNull(message="Please enter advance date")
private Date advance_date;
@Column(name = "amount")
@NotNull(message="Please enter Paid Amount")
private Double amount;
@Column(name = "cheque_date")
@DateTimeFormat(pattern = "dd-MMM-yyyy")
private Date cheque_date;
@Column(name = "cheque_no")
private String cheque_no;
@Column(name = "remarks")
private String remarks;
public AdvanceSalary() {
}
public AdvanceSalary(Integer advance_salary_id) {
this.id = advance_salary_id;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
public Long getEmployee_id() {
return employee_id;
}
public void setEmployee_id(Long employee_id) {
this.employee_id = employee_id;
}
}
부모 개체를 유지하지 못했지만 자식을 저장하는 경우이 예외에 직면했습니다. 이 문제를 해결하기 위해 동일한 세션에서 자식 및 부모 개체를 모두 유지하고 부모에서 CascadeType.ALL을 사용했습니다.
사례 1 : 부모를 만들고 그 부모 참조를 자식과 다른 DELETE / UPDATE 쿼리 (JPQL)에 저장하려고 할 때이 예외가 발생했습니다. 따라서 부모를 만든 후 동일한 부모 참조를 사용하여 자식을 만든 후 새로 만든 엔터티를 플러시합니다. 그것은 나를 위해 일했다.
사례 2 :
학부모 수업
public class Reference implements Serializable {
@Id
@Column(precision=20, scale=0)
private BigInteger id;
@Temporal(TemporalType.TIMESTAMP)
private Date modifiedOn;
@OneToOne(mappedBy="reference")
private ReferenceAdditionalDetails refAddDetails;
.
.
.
}
어린이 수업 :
public class ReferenceAdditionalDetails implements Serializable{
private static final long serialVersionUID = 1L;
@Id
@OneToOne
@JoinColumn(name="reference",referencedColumnName="id")
private Reference reference;
private String preferedSector1;
private String preferedSector2;
.
.
}
위의 경우 OneToOne 관계가있는 parent (Reference) 및 child (ReferenceAdditionalDetails)이고 Reference 엔터티를 만든 다음 해당 자식 (ReferenceAdditionalDetails)을 만들려고하면 동일한 예외가 발생합니다. 따라서 예외를 피하려면 하위 클래스에 대해 null을 설정 한 다음 상위 클래스를 작성해야합니다. (샘플 코드)
.
.
reference.setRefAddDetails(null);
reference = referenceDao.create(reference);
entityManager.flush();
.
.
내 문제는 @BeforeEach
JUnit 과 관련이 있습니다. 그리고 관련 엔터티 (내 경우 @ManyToOne
)를 저장하더라도 동일한 오류가 발생합니다.
문제는 어떻게 든 부모님의 시퀀스와 관련이 있습니다. 해당 속성에 값을 할당하면 문제가 해결됩니다.
전의. 일부 카테고리 (하나 이상)를 가질 수있는 엔티티 질문이 있고 엔티티 질문에 시퀀스가있는 경우 :
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "feedbackSeq")
@Id
private Long id;
값을 할당해야합니다 question.setId(1L);