Lợi thế của việc tồn tại () so với save () trong Hibernate là gì?


Câu trả lời:


154

Từ bài viết diễn đàn này

persist()được xác định rõ. Nó làm cho một ví dụ thoáng qua liên tục. Tuy nhiên, điều đó không đảm bảo rằng giá trị định danh sẽ được gán cho thể hiện liên tục ngay lập tức, việc gán có thể xảy ra vào thời điểm xả. Thông số kỹ thuật không nói rằng, đó là vấn đề tôi gặp phải persist().

persist()cũng đảm bảo rằng nó sẽ không thực thi câu lệnh INSERT nếu nó được gọi bên ngoài ranh giới giao dịch. Điều này hữu ích trong các cuộc hội thoại dài với bối cảnh Phiên / kéo dài.

Một phương pháp như persist()được yêu cầu.

save()không đảm bảo giống nhau, nó trả về một mã định danh và nếu phải thực hiện INSERT để nhận mã định danh (ví dụ: trình tạo "nhận dạng", không phải "chuỗi"), thì INSERT này xảy ra ngay lập tức, bất kể bạn đang ở trong hay ngoài Một giao dịch. Điều này không tốt trong một cuộc trò chuyện dài với bối cảnh Phiên / kiên trì mở rộng.


44
để thêm nhiều hơn từ cùng một bài đăng, để than vãn: "Đáng buồn thay, 5 năm sau, chủ đề này vẫn là nguồn thông tin rõ ràng duy nhất về chủ đề này. Tài liệu Hibernate, trong khi dài dòng, không có giá trị nào ngoài thông tin sử dụng tầm thường nhất. Tại sao bài đăng cuối cùng của christian không có trong Phiên javadoc chỉ là một bí ẩn tài liệu Hibernate khác. "
kommradHomer

bạn có nghĩa là phương thức contin () sẽ làm cho thực thể ở trạng thái tách rời và save () ở trạng thái đính kèm?
rekinyz

2
Gần đây tôi đã sử dụng cả lưu và duy trì trong ánh xạ hai chiều. tôi phát hiện ra rằng lưu không xếp tầng cho trẻ, nghĩa là chỉ có Cha mẹ được lưu / chèn vào bảng. Tuy nhiên, vẫn kiên trì hoàn thành nhiệm vụ cứu cả Cha mẹ và Con cái trong một cuộc gọi. Tôi đang sử dụng ID tổng hợp không phải là ID được tạo.
arn-arn

68

Tôi đã thực hiện nghiên cứu tốt về save () vs contin () bao gồm chạy nó trên máy cục bộ của tôi nhiều lần. Tất cả các giải thích trước đây là khó hiểu và không chính xác. Tôi đã so sánh lưu () và kiên trì () bên dưới sau khi nghiên cứu kỹ lưỡng.

Save()

  1. Trả về Id được tạo sau khi lưu. Kiểu Serializabletrả về của nó .
  2. lưu các thay đổi vào db bên ngoài giao dịch.
  3. Gán id được tạo cho thực thể bạn đang tồn tại
  4. Session.save () cho một đối tượng tách rời sẽ tạo ra một hàng mới trong bảng.

Persist()

  1. Không trả lại Id được tạo sau khi lưu. Loại trả về void của nó.
  2. Không lưu các thay đổi vào db bên ngoài giao dịch.
  3. Chỉ định generated idcho thực thể bạn đang tồn tại
  4. session.persist()cho một đối tượng tách ra sẽ ném PersistentObjectExceptionvì nó không được phép.

Tất cả những điều này đã được thử / thử nghiệm trên Hibernate v4.0.1.


Điểm 3 cho Save () và Persist () được đề cập nhưng chúng không thực sự giống nhau. Phương thức Persist () lưu các thay đổi vào db bên ngoài giao dịch.
Ravi.Kumar

2
khi tôi đã kiểm tra sau khi thực hiện giao dịch bằng cách sử dụng giá trị phương thức bền vững không được lưu vào DB
Laxminarayana Challagonda

Vậy # 1 và # 5 là sự khác biệt thực sự giữa hai? Nếu bạn cần một id được trả về hoặc một hàng mới được tạo, hãy sử dụng Save()?
user2490003

Làm thế nào Save () # 3 có thể giao dịch bên ngoài
vikas singh

24

Tôi đã làm một số thử nghiệm giả để ghi lại sự khác biệt giữa save()persist().

Âm thanh giống như cả hai phương thức này hoạt động giống nhau khi giao dịch với Thực thể thoáng qua nhưng khác nhau khi giao dịch với Thực thể tách rời.

Ví dụ bên dưới, hãy lấy EmployeeVehicle làm Thực thể với PK là vehicleId là giá trị được tạo và vehicleNamelà một trong các thuộc tính của nó.

Ví dụ 1: Xử lý đối tượng thoáng qua

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

Kết quả:

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

Lưu ý kết quả là giống nhau khi bạn nhận được một đối tượng đã tồn tại và lưu nó

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

Lặp lại tương tự bằng cách sử dụng persist(entity) và sẽ cho kết quả tương tự với Id mới (giả sử 37, honda);

Ví dụ 2: Xử lý vật thể tách rời

// 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();

Kết quả: Bạn có thể mong đợi Xe có id: 36 thu được trong phiên trước được cập nhật với tên là "Toyota". Nhưng điều xảy ra là một thực thể mới được lưu trong DB với Id mới được tạo và đặt tên là "Toyota"

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

Sử dụng liên tục để liên tục tách rời thực thể

// (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();

Kết quả:

Exception being thrown : detached entity passed to persist

Vì vậy, tốt hơn hết là sử dụng Persist () thay vì Save () vì lưu phải được sử dụng cẩn thận khi làm việc với đối tượng Transient.

Lưu ý quan trọng: Trong ví dụ trên, pk của thực thể phương tiện là một giá trị được tạo, vì vậy khi sử dụng save () để duy trì một thực thể tách rời, hibernate tạo ra một id mới để tồn tại. Tuy nhiên, nếu pk này không phải là một giá trị được tạo ra thì nó sẽ dẫn đến một khóa ghi ngoại lệ bị vi phạm.


12

Câu hỏi này có một số câu trả lời tốt về các phương pháp kiên trì khác nhau trong Hibernate. Để trả lời câu hỏi của bạn trực tiếp, với save (), câu lệnh chèn được thực thi ngay lập tức bất kể trạng thái giao dịch. Nó trả về khóa được chèn để bạn có thể làm một cái gì đó như thế này:

long newKey = session.save(myObj);

Vì vậy, sử dụng save () nếu bạn cần một mã định danh được gán cho thể hiện liên tục ngay lập tức.

Với contin (), câu lệnh chèn được thực thi trong một giao dịch, không nhất thiết phải ngay lập tức. Điều này là thích hợp hơn trong hầu hết các trường hợp.

Sử dụng kiên trì () nếu bạn không cần chèn để xảy ra ngoài chuỗi với giao dịch và bạn không cần trả lại khóa được chèn.


6

Dưới đây là những khác biệt có thể giúp bạn hiểu được những lợi thế của phương pháp lưu và lưu:

  • Sự khác biệt đầu tiên giữa lưu và tồn tại là loại trả về của họ. Kiểu trả về của phương thức kiên trì là void trong khi kiểu trả về
    phương thức là đối tượng Nối tiếp.
  • Phương thức contin () không đảm bảo rằng giá trị định danh sẽ được gán cho trạng thái liên tục ngay lập tức, việc gán có thể xảy ra vào thời gian xả.

  • Phương thức contin () sẽ không thực hiện truy vấn chèn nếu nó được gọi bên ngoài ranh giới giao dịch. Trong khi, phương thức save () trả về một mã định danh để một truy vấn chèn được thực thi ngay lập tức để lấy mã định danh, bất kể nó nằm trong hay bên ngoài giao dịch.

  • Phương thức bền vững được gọi bên ngoài ranh giới giao dịch, nó hữu ích trong các cuộc hội thoại dài với bối cảnh Phiên mở rộng. Mặt khác, phương thức lưu không tốt trong một cuộc trò chuyện dài với bối cảnh Phiên mở rộng.

  • Sự khác biệt thứ năm giữa phương thức lưu và duy trì trong Hibernate: kiên trì được hỗ trợ bởi JPA, trong khi lưu chỉ được Hibernate hỗ trợ.

Bạn có thể xem ví dụ hoạt động đầy đủ từ bài đăng Sự khác biệt giữa phương thức lưu và duy trì trong Hibernate


Trước tiên, bạn nói "Phương thức contin () sẽ không thực hiện truy vấn chèn nếu nó được gọi bên ngoài ranh giới giao dịch". Sau đó, bạn nói "Phương thức liên tục được gọi bên ngoài ranh giới giao dịch, nó hữu ích trong các cuộc hội thoại dài với bối cảnh Phiên mở rộng." Không phải họ mâu thuẫn sao? Tôi không hiểu
Kumar Manish

@KumarM Biến Trong trường hợp phương thức kiên trì, một truy vấn chèn xảy ra vào thời gian xả. Vì vậy, đó là một cách thực hành tốt nhất trong các cuộc trò chuyện dài
David Phạm

5

save () - Như tên phương thức gợi ý, hibernate save () có thể được sử dụng để lưu thực thể vào cơ sở dữ liệu. Chúng ta có thể gọi phương thức này bên ngoài một giao dịch. Nếu chúng tôi sử dụng điều này mà không có giao dịch và chúng tôi có xếp tầng giữa các thực thể, thì chỉ có thực thể chính được lưu trừ khi chúng tôi xóa phiên.

kiên trì () - Hibernate vẫn tương tự như lưu (với giao dịch) và nó thêm đối tượng thực thể vào bối cảnh liên tục, do đó, mọi thay đổi tiếp theo đều được theo dõi. Nếu các thuộc tính đối tượng được thay đổi trước khi giao dịch được thực hiện hoặc phiên bị xóa, nó cũng sẽ được lưu vào cơ sở dữ liệu. Ngoài ra, chúng ta chỉ có thể sử dụng phương thức kiên trì () trong phạm vi giao dịch, vì vậy nó an toàn và chăm sóc mọi đối tượng xếp tầng. Cuối cùng, kiên trì không trả về bất cứ điều gì vì vậy chúng ta cần sử dụng đối tượng kiên trì để lấy giá trị định danh được tạo.


5

Đây là sự khác biệt:

  1. tiết kiệm:

    1. sẽ trả về id / định danh khi đối tượng được lưu vào cơ sở dữ liệu.
    2. cũng sẽ lưu lại khi đối tượng được cố gắng làm tương tự bằng cách mở một phiên mới sau khi nó bị tách ra.
  2. Kiên trì:

    1. sẽ trả về void khi đối tượng được lưu vào cơ sở dữ liệu.
    2. sẽ ném PersistentObjectException khi cố gắng lưu đối tượng tách ra thông qua một phiên mới.

Bạn có thể vui lòng hiển thị một ví dụ với một đoạn trích. Điều đó sẽ hữu ích.
Avikool91

5

Quy tắc cơ bản nói rằng:

Đối với các Thực thể có mã định danh được tạo:

save (): Nó trả về định danh của một thực thể ngay lập tức ngoài việc làm cho đối tượng liên tục. Vì vậy, một truy vấn chèn được kích hoạt ngay lập tức.

kiên trì (): Nó trả về đối tượng liên tục. Nó không có bất kỳ sự bắt buộc nào về việc trả lại mã định danh ngay lập tức nên không đảm bảo rằng chèn sẽ bị loại bỏ ngay lập tức. Nó có thể bắn một chèn ngay lập tức nhưng nó không được bảo đảm. Trong một số trường hợp, truy vấn có thể bị hủy ngay lập tức trong khi trong các trường hợp khác, truy vấn có thể bị hủy vào thời gian xả phiên.

Đối với các Thực thể có định danh được chỉ định:

save (): Nó trả về định danh của một thực thể ngay lập tức. Vì mã định danh đã được gán cho thực thể trước khi gọi lưu, nên chèn không được kích hoạt ngay lập tức. Nó được bắn vào thời gian tuôn ra phiên.

kiên trì (): giống như lưu. Nó cũng cháy chèn vào thời gian xả.

Giả sử chúng ta có một thực thể sử dụng một định danh được tạo như sau:

@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;
    }
}

tiết kiệm() :

    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();

kiên trì ():

    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();

Bây giờ, giả sử chúng ta có cùng một thực thể được xác định như sau mà không có trường id đã tạo chú thích tức là ID sẽ được gán thủ công.

@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;
    }
}

để lưu ():

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();

cho kiên trì ():

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();

Các trường hợp trên là đúng khi lưu hoặc lưu được gọi từ trong một giao dịch.

Các điểm khác biệt khác giữa lưu và tồn tại là:

  1. save () có thể được gọi bên ngoài một giao dịch. Nếu định danh được gán được sử dụng thì vì id đã có sẵn, do đó không có truy vấn chèn nào được kích hoạt ngay lập tức. Truy vấn chỉ được kích hoạt khi phiên được xóa.

  2. Nếu định danh được tạo được sử dụng, thì vì id cần được tạo, nên chèn ngay lập tức. Nhưng nó chỉ lưu thực thể chính. Nếu thực thể có một số thực thể xếp tầng thì chúng sẽ không được lưu trong db tại thời điểm này. Chúng sẽ được lưu khi phiên bị xóa.

  3. Nếu vẫn tồn tại () bên ngoài một giao dịch thì chèn chỉ được kích hoạt khi phiên được xóa bất kể loại định danh (được tạo hoặc gán) nào được sử dụng.

  4. Nếu lưu được gọi qua một đối tượng liên tục, thì thực thể được lưu bằng truy vấn cập nhật.


2

Trên thực tế, sự khác biệt giữa các phương thức hibernate save () và contin () phụ thuộc vào lớp trình tạo mà chúng ta đang sử dụng.
Nếu lớp trình tạo của chúng ta được gán, thì không có sự khác biệt giữa các phương thức save () và contin (). Bởi vì 'được chỉ định' của trình tạo, với tư cách là một lập trình viên, chúng ta cần cung cấp giá trị khóa chính để lưu trong cơ sở dữ liệu ngay [Hy vọng bạn biết khái niệm trình tạo này] Trong trường hợp khác với lớp trình tạo được gán, giả sử nếu tên lớp trình tạo của chúng ta là Tăng Chính hibernate sẽ gán giá trị id khóa chính vào cơ sở dữ liệu ngay [ngoài trình tạo được gán, hibernate chỉ được sử dụng để chăm sóc giá trị id khóa chính], vì vậy trong trường hợp này, nếu chúng ta gọi phương thức save () hoặc contin (), thì nó sẽ chèn bản ghi vào cơ sở dữ liệu bình thường.
Nhưng ở đây, điều là, phương thức save () có thể trả về giá trị id khóa chính được tạo bởi hibernate và chúng ta có thể thấy nó bằng
long s = session.save (k);
Trong trường hợp tương tự, kiên trì () sẽ không bao giờ trả lại bất kỳ giá trị nào cho máy khách, trả về kiểu void.
vẫn tồn tại () cũng đảm bảo rằng nó sẽ không thực thi câu lệnh INSERT nếu nó được gọi bên ngoài ranh giới giao dịch.
trong khi đó trong save (), INSERT xảy ra ngay lập tức, bất kể bạn đang ở trong hay ngoài giao dịch.


1

Nó hoàn toàn trả lời trên cơ sở loại "trình tạo" trong ID trong khi lưu trữ bất kỳ thực thể nào. Nếu giá trị cho trình tạo được "gán", có nghĩa là bạn đang cung cấp ID. Sau đó, nó làm cho không có khác biệt trong ngủ đông để lưu hoặc tiếp tục. Bạn có thể đi với bất kỳ phương pháp nào bạn muốn. Nếu giá trị không được "gán" và bạn đang sử dụng save () thì bạn sẽ nhận được ID là trả về từ hoạt động save ().

Một kiểm tra khác là nếu bạn đang thực hiện các hoạt động bên ngoài giới hạn giao dịch hay không. Bởi vì contin () thuộc về JPA trong khi save () cho chế độ ngủ đông. Vì vậy, sử dụng kiên trì () bên ngoài ranh giới giao dịch sẽ không cho phép thực hiện và ném ngoại lệ liên quan đến liên tục. trong khi với save () không có hạn chế nào như vậy và người ta có thể đi với giao dịch DB thông qua save () ngoài giới hạn giao dịch.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.