Phân biệt save, persist, update, merge, saveOrUpdate trong hibernate

6909

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Ở 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.

  Cài đặt và sử dụng Hibernate

  Các Annotation của Hibernate

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

Xem thêm nhiều việc làm Data Engineer lương cao trên TopDev

Các trạng thái của 1 thể hiện Entity

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

Method save là một method gốc trong đặc tả của JPA

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("Mar

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

Cũng giống như method persist và save, method update là method gốc trong đặc tả JPA
Nó giống với method merge và đã có từ khá lâu trước khi method merge được thêm vào, 1 số ý nghĩa khác của method update là:
  • 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

Chúng ta đã thảo luận mục đích của sự khác nhau trong các method của Hibernate Session. Các trạng thái của object trong persistence context, sự chuyển đổi giữa các trạng thái và tại sao lại có các method có chức năng giống nhau. Phân biệt save, persist, update, merge, saveOrUpdate trong hibernate.

Bài viết gốc được đăng tải tại stackjava.com