Câu trả lời:
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ảipersist()
.
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.
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()
Serializable
trả về của nó .Persist()
generated id
cho thực thể bạn đang tồn tạisession.persist()
cho một đối tượng tách ra sẽ ném PersistentObjectException
vì 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
.
Save()
?
Tôi đã làm một số thử nghiệm giả để ghi lại sự khác biệt giữa save()
và 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à vehicleName
là 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.
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.
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:
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
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.
Đây là sự khác biệt:
tiết kiệm:
Kiên trì:
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à:
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.
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.
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.
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.
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.
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.