Phân biệt save, persist, update, merge, saveOrUpdate trong hibernate
Ở bài này chúng ta sẽ thảo luận về sự khác nhau giữa vài method của Session interface: save, persist, update, merge, saveOrUpdate.
(Các framework ORM khác có thể không dùng interface session mà dùng interface entityManager nên sẽ có sự khác nhau giữa tên của các method)
1. Session là 1 cài đặt của Persitence Context
Session interface có một và method thực hiện lưu dữ liệu vào database như persist, save, update, merge, saveOrUpdate
. Để hiểu sự khác nhau giữa những method này trước hết ta cần phải hiểu mục đích của Session interface và các trạng thái/quan hệ của 1 thể hiện entity với Session
Chúng ta cũng nên hiểu một chút về lịch sử phát triển của Hibernate, điều gì dẫn tới sự trùng lặp một số API method.
1.1. Quản lý các thể hiện entity
Ngoài mối quan hệ giữa các object, một vấn đề khác được Hibernate dự định giải quyết là vấn đề quản lý các entity trong thời gian chạy (runtime). Khái nhiệm “persistence context” là giải pháp của Hibernate cho vấn đề này. Persistence context có thể hiểu như là 1 container hoặc mức cache đầu tiên cho tất cả các object mà ta đã tải hoặc save vào database trong 1 session.
Session là 1 lý luận transaction, nó bao là ranh giới để định nghĩa logic nghiệp vụ của ứng dụng của bạn. Khi bạn làm việc với database thông qua một persistence context và tất cả các thể hiện entity đều được gán với context, bạn nên có 1 thể hiện phân biệt của entity cho mỗi bản ghi database mà bạn giao tiếp trong suốt suốt session.
Trong Hibernate, persistence context được thể hiện bới org.hibernate.Session. Với JPA, nó là javax.persistence.EntityManager.
1.2 Các trạng thái của 1 thể hiện Entity
Trong 1 Session persistence context, các entity có 4 trạng thái:
- transient: đối tượng chưa bao giờ bị quản lí bởi session và nó không tương ứng với bản ghi nào trong database; thông thường đây là 1 đối tượng mới được tạo để save vào database
- persistent: đối tượng bị quản lý bởi session và là unique (trong 1 session không thể tồn tại 2 object có cùng id), sau khi flush bởi session sẽ tồn tại 1 bản ghi tương ứng đối tượng này trong database.
- detached: đối tượng này đã từng bị quản lý bởi session nhưng hiện tại thì không. (bị evict(), clear(), close())
- removed:cũng giống như detached nhưng bản ghi tương ứng với đối tượng này trước đó đã bị xóa khỏi database. (bị remove())
1.3. Sự phù hợp với đặc tả của JPA
Hibernate là cài đặt ORM Java thành công nhất. Không ngạc nhiên khi mà các đặc tả cho Java persistence API (JPA) bị ảnh hưởng nhiều bởi Hibernate API. Cũng không ngạc nhiên khi Hibernate là ORM Framework phổ biến nhất.
Để thực hiện các cài đặt theo chuẩn của JPA, nhiều Hibernate API phải sửa lại. Một vài method được thêm vào Session interface để khớp với EntityManager interface. Những method này phục vụ các mục đích giống với method gốc.
2. Sự khác nhau giữa các hành động thực thi
Các method persist, save, update, merge, saveOrUpdate
không lập tức đưa ra kết quả tương ứng SQL UPDATE hoặc INSERT. Thực tế thì việc cập nhật dữ liệu vào database xảy ra khi transaction được commit hoặc flushing session.
2.1. Persist
Method persist
được dùng để thêm 1 thể hiện entity mới vào persistence context (ví dụ chuyển trạng thái của entity từ transient sang persistent
Chúng ta thường gọi method này khi chúng ta muốn thêm 1 bản ghi vào database:
Person person = new Person(); person.setName("John"); session.persist(person);
Điều gì xảy ra sau khi method persist
được gọi? Đối tượng person bị đổi trạng thái từ transient sang persistent. Đối tượng vào trong persistence context nhưng vẫn chưa được lưu vào database. Thông thường lệnh INSERT sẽ chỉ xuất hiện khi commit transaction hoặc flushing/close session.
Lưu ý rằng persist method trả về kiểu void.
Ý nghĩa của method persist:
- Thay đổi trạng thái 1 đối tượng từ transient sang persistent (và thực hiện cascades tới tất cả các relations của nó nếu cascade = PERSIST hoặc cascade = ALL)
- Nếu đối tượng đã là persistent thì nó không làm gì cả (nhưng vẫn thực hiện cascades tới tất cả các relations của nó nếu cascade = PERSIST hoặc cascade = ALL)
- Nếu đối tượng là detached nó sẽ xảy ra exception khi gọi method hoặc khi commit hoặc khi flushing session.
Person person = new Person(); person.setName("John"); session.persist(person); session.evict(person); session.persist(person); // PersistenceException!
2.2. Save
Mục đích cơ bản của method save giống với persist, tuy nhiên nó có sự khác nhau trong cài đặt chi tiết. Tài liệu cho method này nhấn mạnh rằng nó persists 1 thể hiện (hiểu nôm na là nó sẽ tạo ra 1 định danh mới cho thể hiện)
Person person = new Person(); person.setName("John"); Long id = (Long) session.save(person);
Nó khác với method persist khi bạn cố gắng save 1 thể hiện detached:
Person person = new Person(); person.setName("John"); Long id1 = (Long) session.save(person); session.evict(person); Long id2 = (Long) session.save(person);
Giá trị của id2 sẽ khác với id1. Khi gọi method save 1 thể hiện detached nó sẽ tạo ra 1 thể hiện persistent và chỉ định cho một định danh/id mới. Kết quả là tạo ra 2 bản ghi vào database khi commit hoặc flushing.
2.3. Merge
Mục đích chính của method merge
là update một thể hiện entity có trạng thái persistent vào 1 một thể hiện entity có trạng thái detached.
Trong ví dụ dưới đây, chúng ta eviect(detach) 1 entity đã saved, thay đổi name và merge.
Person person = new Person(); person.setName("John"); session.save(person); session.evict(person); person.setName("Mary"); Person mergedPerson = (Person) session.merge(person);
Lưu ý rằng method merge trả về 1 đối tượng, đó là đối tượng đã được merge không phải đối tượng truyền vào.
2.4. Update
- Trả về kiểu void, thay đổi trạng thái của object truyền vào từ detached sang persistent
Person person = new Person(); person.setName("John"); session.save(person); session.evict(person); person.setName("Mary"); session.update(person);
- Xảy ra exception nếu bạn truyền vào 1 đối tượng transient.
Person person = new Person(); person.setName("John"); session.update(person); // PersistenceException!
2.5. saveOrUpdate
Method saveOrUpdate chỉ xuất hiện trong Hibernate API và không có
Điểm khác chính của method saveOrUpdate là nó không xảy ra exception khi truyền vào 1 đối tượng transient. Thay vì đó, nó sẽ tạo ra 1 thể hiện persistent
Person person = new Person(); person.setName("John"); session.saveOrUpdate(person);
3. Kết luận
Liên quan: Sự khác nhau giữa merge với saveOrUpdate trong Hibernate
References:
http://www.baeldung.com/hibernate-save-persist-update-merge-saveorupdate
http://www.java67.com/2016/01/difference-between-save-saveorupdate-and-persist-in-Hibernate.html