Hibernate에서 persist () 대 save ()의 장점은 무엇입니까?


답변:


154

에서 이 포럼 게시물

persist()잘 정의되어 있습니다. 임시 인스턴스를 지속적으로 만듭니다. 그러나 식별자 값이 영구 인스턴스에 즉시 할당되는 것을 보장하지는 않으며 할당시 플러시 시간이 발생할 수 있습니다. 사양에 나와 있지 않은 문제가 있습니다 persist().

persist()또한 트랜잭션 경계 외부에서 호출 된 경우 INSERT 문을 실행하지 않도록 보장합니다. 이것은 확장 된 세션 / 지속성 컨텍스트를 가진 장기 대화에서 유용합니다.

같은 방법 persist()이 필요합니다.

save()동일한 것을 보장하지 않고, 식별자를 반환하며, 식별자를 얻기 위해 INSERT를 실행해야하는 경우 (예 : "시퀀스"가 아닌 "ID"생성기)이 INSERT는 내부 또는 외부에 관계없이 즉시 발생합니다. 거래. 확장 된 세션 / 지속성 컨텍스트를 가진 장기 대화에서는 좋지 않습니다.


44
같은 게시물에서 더 많은 정보를 추가하려면 다음과 같이 덧붙입니다. "슬프게도, 5 년이 지난 후에도이 스레드는 여전히이 주제에 관한 유일한 정보 소스입니다. Hibernate 문서는 자세하게 설명하지만 가장 사소한 사용 정보를 제외한 모든 정보가 없습니다. Christian의 마지막 게시물이 세션에없는 이유 javadoc은 또 다른 Hibernate 문서의 미스터리입니다. "
kommradHomer

persist () 메소드가 엔티티를 분리 상태로 만들고 save ()를 첨부 상태로 만들 것입니까?
rekinyz

2
최근에 일대 다 양방향 매핑에서 저장 및 지속 기능을 모두 사용했습니다. 저장이 하위 항목에 계단식으로 배열되지 않는다는 것을 알았습니다. 즉, 부모 만 테이블에 저장 / 삽입됩니다. 그러나 한 번의 호출로 부모와 자식을 모두 저장하는 작업을 지속하십시오. 생성 된 ID가 아닌 복합 ID를 사용하고 있습니다.
arn-arn

68

로컬 컴퓨터에서 여러 번 실행하는 것을 포함하여 save () vs persist ()에 대한 훌륭한 연구를 수행했습니다. 이전의 모든 설명이 혼란스럽고 정확하지 않습니다. 철저한 연구 끝에 아래 save () 및 persist ()를 비교했습니다.

Save()

  1. 저장 후 생성 된 ID를 반환합니다. 그것의 Serializable반환 형식.
  2. 트랜잭션 외부의 DB에 변경 사항을 저장하십시오.
  3. 생성 된 ID를 유지중인 엔티티에 할당
  4. 분리 된 객체에 대한 Session.save ()는 테이블에 새로운 행을 만듭니다.

Persist()

  1. 저장 후 생성 된 ID를 반환하지 않습니다. void 리턴 타입입니다.
  2. 트랜잭션 외부의 DB에 대한 변경 사항을 저장하지 않습니다.
  3. generated id지속중인 엔터티 에을 할당합니다
  4. session.persist()분리 된 객체는 PersistentObjectException허용되지 않으므로 throw 됩니다.

이 모든 것은에 시도 / 테스트되었습니다 Hibernate v4.0.1.


Save () 및 Persist ()에 대한 포인트 3은 언급되었지만 실제로는 동일하지 않습니다. Persist () 메소드는 트랜잭션 외부의 db에 대한 변경 사항도 저장합니다.
Ravi. Kumar

2
persist 메소드 값을 사용하여 트랜잭션을 커밋 한 후 테스트 할 때 DB에 저장되지 않습니다.
Laxminarayana Challagonda

그래서 # 1과 # 5는이 둘의 실제 차이점입니까? 아이디가 반환되거나 새 행이 생성되면 Save()?를 사용하십시오 .
user2490003

거래 외의 Save () # 3 방법
vikas singh

24

나는 사이의 차이를 기록하는 테스트 일부 모의 한 save()persist().

이 두 가지 방법 모두 일시적인 엔티티를 처리 할 때 동일하게 동작하지만 분리 된 엔티티를 처리 할 때는 다릅니다.

아래 예의 경우 EmployeeVehicle을 vehicleId생성 된 값인 PK를 가진 엔티티 및 vehicleName특성 중 하나로 사용하십시오.

예 1 : 과도 객체 다루기

Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = new EmployeeVehicle();
entity.setVehicleName("Honda");
session.save(entity);
// session.persist(entity);
session.getTransaction().commit();
session.close();

결과:

select nextval ('hibernate_sequence') // This is for vehicle Id generated : 36
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Honda, 36)

이미 유지 된 객체를 가져 와서 저장할 때 결과는 동일합니다.

EmployeeVehicle entity =  (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
entity.setVehicleName("Toyota");
session.save(entity);    -------> **instead of session.update(entity);**
// session.persist(entity);

같은 것을 반복해서 사용 persist(entity)하면 새로운 Id와 같은 결과가 나옵니다 (37, 혼다).

예 2 : 분리 된 객체 다루기

// Session 1 
// Get the previously saved Vehicle Entity 
Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
session.close();

// Session 2
// Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
// (i) Using Save() to persist a detached object 
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.save(entity);
session2.getTransaction().commit();
session2.close();

결과 : 이전 세션에서 얻은 id : 36의 차량이 "Toyota"라는 이름으로 업데이트 될 것으로 예상 할 수 있습니다. 그러나 새로운 엔티티가 생성되고 이름이 "Toyota"인 새 엔티티가 DB에 저장됩니다.

select nextval ('hibernate_sequence')
insert into Employee_Vehicle ( Vehicle_Name, Vehicle_Id) values ( Toyota, 39)

지속성을 사용하여 분리 된 엔티티 유지

// (ii) Using Persist()  to persist a detached
// Session 1 
Session session = factory.openSession();
session.beginTransaction();
EmployeeVehicle entity = (EmployeeVehicle)session.get(EmployeeVehicle.class, 36);
session.close();

// Session 2
// Here in Session 2 , vehicle entity obtained in previous session is a detached object and now we will try to save / persist it 
// (i) Using Save() to persist a detached
Session session2 = factory.openSession();
session2.beginTransaction();
entity.setVehicleName("Toyota");
session2.persist(entity);
session2.getTransaction().commit();
session2.close();

결과:

Exception being thrown : detached entity passed to persist

따라서 Transient 객체를 다룰 때 save를 신중하게 사용해야하므로 Save () 대신 Persist ()를 사용하는 것이 좋습니다.

중요 참고 : 위 예제에서 비히클 엔터티의 pk는 생성 된 값이므로 save ()를 사용하여 분리 된 엔터티를 유지하면 최대 절전 모드에서 유지하기 위해 새 ID가 생성됩니다. 그러나이 pk가 생성 된 값이 아닌 경우 키를 위반 한 예외가 발생합니다.


13

이 질문 에는 최대 절전 모드의 다양한 지속성 방법에 대한 좋은 답변이 있습니다. 질문에 직접 대답하기 위해 save ()를 사용하면 트랜잭션 상태에 관계없이 insert 문이 즉시 실행됩니다. 삽입 된 키를 반환하므로 다음과 같이 할 수 있습니다.

long newKey = session.save(myObj);

따라서 영구 인스턴스에 즉시 할당 된 식별자가 필요한 경우 save ()를 사용하십시오.

persist ()를 사용하면 insert 문이 트랜잭션에서 실행되지만 반드시 즉시 실행되는 것은 아닙니다. 대부분의 경우에 바람직합니다.

트랜잭션에서 삽입이 순서대로 발생하지 않고 삽입 된 키를 리턴 할 필요가없는 경우 persist ()를 사용하십시오.


6

다음은 persist 및 save 메소드의 장점을 이해하는 데 도움이되는 차이점입니다.

  • 저장과 지속의 첫 번째 차이점은 리턴 유형입니다. persist 메소드의 리턴 유형은 void이고 save
    메소드 의 리턴 유형 은 Serializable 오브젝트입니다.
  • persist () 메소드는 식별자 값이 지속적 상태에 즉시 할당되도록 보장하지 않으며, 플러시 시간에 할당이 발생할 수 있습니다.

  • persist () 메소드는 트랜잭션 경계 외부에서 호출 된 경우 삽입 조회를 실행하지 않습니다. 한편 save () 메서드는 식별자를 반환하므로 삽입 쿼리가 트랜잭션 내부 또는 외부에 있더라도 식별자를 얻기 위해 즉시 실행됩니다.

  • persist 메소드는 트랜잭션 경계 외부에서 호출되며, 확장 된 세션 컨텍스트를 가진 장기 대화에서 유용합니다. 반면, 저장 방법은 확장 된 세션 컨텍스트와 장기 실행 대화에 적합하지 않습니다.

  • Hibernate에서 save와 persist 메소드의 다섯 번째 차이점 : persist는 JPA에서 지원되는 반면 save는 Hibernate에서만 지원됩니다.

Hibernate 의 post 와 save 메소드의 차이점에 대한 전체 작업 예를 볼 수 있습니다


먼저 "persist () 메소드는 트랜잭션 경계 밖에서 호출 된 경우 삽입 쿼리를 실행하지 않습니다"라고 말합니다. "영구 메소드는 트랜잭션 경계 밖에서 호출되며, 확장 된 세션 컨텍스트를 가진 장기 대화에서 유용합니다." 모순되지 않습니까? 이해가 안 돼요
Kumar Manish

@KumarManish persist 메소드의 경우 플러시시 삽입 쿼리가 발생합니다. 따라서 장기 대화에서 모범 사례입니다
David Pham

5

save ()-메소드 이름에서 알 수 있듯이 최대 절전 save ()를 사용하여 엔티티를 데이터베이스에 저장할 수 있습니다. 트랜잭션 외부에서이 메소드를 호출 할 수 있습니다. 트랜잭션없이 이것을 사용하고 엔터티간에 계단식이있는 경우 세션을 비우지 않으면 기본 엔터티 만 저장됩니다.

persist ()-Hibernate persist는 저장 (트랜잭션 사용)과 유사하며 엔티티 객체를 지속적 컨텍스트에 추가하므로 추가 변경 사항이 추적됩니다. 트랜잭션이 커밋되거나 세션이 플러시되기 전에 개체 속성이 변경되면 데이터베이스에도 저장됩니다. 또한, 트랜잭션 경계 내에서만 persist () 메소드를 사용할 수 있으므로 안전하고 계단식 객체를 처리합니다. 마지막으로 persist는 아무것도 반환하지 않으므로 생성 된 식별자 값을 얻으려면 persisted 객체를 사용해야합니다.


5

차이점은 다음과 같습니다.

  1. 저장:

    1. 객체가 데이터베이스에 저장되면 id / identifier를 반환합니다.
    2. 개체가 분리 된 후 새 세션을 열어서 동일한 작업을 시도 할 때도 저장됩니다.
  2. 지속 :

    1. 객체가 데이터베이스에 저장되면 void를 반환합니다.
    2. 새 세션을 통해 분리 된 객체를 저장하려고하면 PersistentObjectException이 발생합니다.

스 니펫이 포함 된 예를 보여 주시겠습니까? 유용 할 것입니다.
Avikool91

5

기본 규칙은 다음과 같이 말합니다.

식별자가 생성 된 엔터티 :

save () : 객체를 영속적으로 만드는 것 외에도 엔티티의 식별자를 즉시 ​​반환합니다. 따라서 삽입 쿼리가 즉시 시작됩니다.

persist () : 영속 객체를 반환합니다. 식별자를 즉시 ​​반환해야한다는 강제는 없으므로 삽입이 즉시 발생한다는 보장은 없습니다. 인서트가 즉시 발사 될 수 있지만 보장되지는 않습니다. 경우에 따라 쿼리가 즉시 실행되는 반면 세션 플러시 시간에 실행되는 경우도 있습니다.

식별자가 할당 된 엔터티 :

save () : 엔티티의 식별자를 즉시 ​​반환합니다. save를 호출하기 전에 ID가 이미 엔티티에 지정되었으므로 insert가 즉시 실행되지 않습니다. 세션 플러시 시간에 시작됩니다.

persist () : save와 동일합니다. 또한 세척시 인서트 발사.

다음과 같이 생성 된 식별자를 사용하는 엔티티가 있다고 가정하십시오.

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    @GeneratedValue(strategy=GenerationType.AUTO)
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

저장() :

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.save(user); // Query is fired immediately as this statement is executed.
    session.getTransaction().commit();
    session.close();

persist () :

    Session session = sessionFactory.openSession();
    session.beginTransaction();
    UserDetails user = new UserDetails();
    user.setUserName("Gaurav");
    session.persist(user); // Query is not guaranteed to be fired immediately. It may get fired here.
    session.getTransaction().commit(); // If it not executed in last statement then It is fired here.
    session.close();

이제 ID 필드에 주석을 생성하지 않고 다음과 같이 정의 된 동일한 엔티티가 있다고 가정하십시오. 즉 ID가 수동으로 지정됩니다.

@Entity
@Table(name="USER_DETAILS")
public class UserDetails {
    @Id
    @Column(name = "USER_ID")
    private int userId;

    @Column(name = "USER_NAME")
    private String userName;

    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
}

save () :

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.save(user); // Query is not fired here since id for object being referred by user is already available. No query need to be fired to find it. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();

persist ()의 경우 :

Session session = sessionFactory.openSession();
session.beginTransaction();
UserDetails user = new UserDetails();
user.setUserId(1);
user.setUserName("Gaurav");
session.persist(user); // Query is not fired here.Object is made persistent. Data for user now available in first level cache but not in db.
session.getTransaction().commit();// Query will be fired at this point and data for user will now also be available in DB
session.close();

위의 경우는 트랜잭션 내에서 저장 또는 지속이 호출 된 경우에 해당됩니다.

저장과 지속의 다른 점은 다음과 같습니다.

  1. save ()는 트랜잭션 외부에서 호출 할 수 있습니다. 할당 된 식별자를 사용하면 id를 이미 사용할 수 있으므로 삽입 쿼리가 즉시 실행되지 않습니다. 세션이 플러시 될 때만 쿼리가 시작됩니다.

  2. 생성 된 식별자가 사용되면 id가 생성되어야하므로 insert가 즉시 실행됩니다. 그러나 기본 엔터티 만 저장합니다. 엔터티에 계단식 엔터티가 있으면이 시점에서 db에 저장되지 않습니다. 세션이 플러시 될 때 저장됩니다.

  3. persist ()가 트랜잭션 외부에 있으면 어떤 종류의 식별자 (생성 또는 할당)가 사용되는지에 관계없이 세션이 플러시 될 때만 insert가 시작됩니다.

  4. 영구 객체를 통해 save를 호출하면 업데이트 쿼리를 사용하여 엔터티가 저장됩니다.


2

실제로 최대 절전 모드 save ()와 persist () 메서드의 차이점은 사용중인 생성기 클래스에 따라 다릅니다.
생성기 클래스가 할당되면 save ()와 persist () 메소드 사이에 차이가 없습니다. 생성자 '할당 됨'은 프로그래머로서 데이터베이스에 저장할 기본 키 값을 제공해야합니다. [이 생성기 개념을 알고 싶습니다.] 생성 된 생성기 클래스가 아닌 경우 생성기 클래스 이름이 증가 평균 인 경우를 가정하십시오. 최대 절전 모드 자체는 기본 키 ID 값을 데이터베이스 권한에 할당합니다 (할당 된 생성기 이외의 경우 최대 절전 키는 기본 키 ID 값을 관리하는 데만 사용됨).이 경우 save () 또는 persist () 메서드를 호출하면 데이터베이스에 레코드를 정상적으로 삽입합니다.
그러나 여기서, save () 메소드는 최대 절전 모드에서 생성 된 기본 키 ID 값을 반환 할 수 있으며
long s = session.save (k);
이 경우 persist ()는 클라이언트에게 값을 돌려주지 않으며 void 유형을 반환합니다.
persist ()는 또한 트랜잭션 경계 외부에서 호출되는 경우 INSERT 문을 실행하지 않도록 보장합니다.
반면 save ()에서는 트랜잭션 내부 또는 외부에 관계없이 INSERT가 즉시 발생합니다.


1

엔티티를 저장하는 동안 ID의 "제너레이터"유형을 기반으로 완전히 응답했습니다. generator의 값이 "지정된"경우 ID를 제공한다는 의미입니다. 그런 다음 저장하거나 유지하기 위해 최대 절전 모드로 전환하지 않습니다. 원하는 방법으로 갈 수 있습니다. 값이 "할당되지 않고"save ()를 사용하는 경우 save () 작업에서 반환 된 ID를 얻게됩니다.

또 다른 점검은 트랜잭션 한계 밖에서 작업을 수행 중인지 여부입니다. persist ()는 JPA에 속하고 save ()는 최대 절전 모드입니다. 따라서 트랜잭션 경계 외부에서 persist ()를 사용하면 그렇게 할 수 없으며 지속성과 관련된 예외가 발생합니다. save ()를 사용하면 그러한 제한이 없으며 트랜잭션 제한을 벗어난 save ()를 통해 DB 트랜잭션을 사용할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.