Hibernate Lifecycle

Bài viết được sự cho phép của tác giả Giang Phan

Trong Hibernate, chúng ta sẽ tạo một đối tượng từ một Entity (thực thể) và lưu nó vào cơ sở dữ liệu hoặc chúng ta lấy dữ liệu từ cơ sở dữ liệu. Ở đây, mỗi Entity được liên kết với lifecycle (vòng đời), chịu sự quản lý của Session. Đối tượng Entity đi qua các giai đoạn khác nhau của lifecycle. Trong bài viết này, chúng ta sẽ cùng tìm hiểu về các giai đoạn này.

  Hibernate Batch processing
  Hibernate là gì? Sao phải dùng nó thay JDBC?

Giới thiệu Hibernate Lifecycle

Khi nói về trạng thái (state) của object trong Hibernate, chúng ta nói một đối tượng có quan hệ với Session, nghĩa là Session có tham chiếu đến đối tượng đó, hay một cách khác là chịu sự quản lý của Session. Session được coi là một loại của Persistence Context.

Quản lý các Entity

Ngoài việc map đối tượng Java đến bản ghi trong CSDL (tức là ORM), thì có một vấn đề mà Hibernate phải care đến đó là quản lý các Entity. Cái ý niệm về “persistence context” chính là giải pháp để giúp Hibernate làm được việc này. Persistence context có thể coi là một “môi trường” chứa toàn bộ các đối tượng mà ta tạo ra và lưu vào csdl trong mỗi session.

Một Session, hay là 1 phiên, là một giao dịch, có phạm vi tùy vào từng ứng dụng. Khi ta làm việc với DB thông qua một Persistence Context, mọi thực-thể sẽ gắn vào context này, mỗi bản ghi trong DB mà ta tương tác sẽ tương ứng với 1 thực thể trong context này.

Trong Hibernate, PersistenceContext được tạo ra nhờ org.hibernate.Session . Với JPA, PersistenceContext được thể hiện thông qua class javax.persistence.EntityManagerJPA là bộ đặc tả cho việc lưu dữ liệu vào DB dành cho ngôn ngữ Java, Hibernate sau này đã tuân theo bộ đặc tả đó. Khi đó nếu dùng combo JPA-Hibernate, thì Persistence Context được tạo ra bởi EntityManager interface, thực tế sẽ là một lớp bọc lấy cái Session object ở phía dưới. Nếu ta xài thẳng Session (ko xài EntityManager) thì sẽ có nhiều phương thức cho ta xài hơn, tiện dụng hơn.

Trạng thái của các Entity

Một đối tượng trong Hibernate có 1 trong 4 trạng thái:

  • Transient (Tạm thời): Đối tượng không có quan hệ với Session hiện tại của Hibernate. Đối tượng ở trạng thái này chưa từng gắn vào context, nó không có bản ghi tương ứng trong CSDL

  • Persistent (Bền vững): Đối tượng đang liên hệ với một context, tức là với một đối tượng Session và trạng thái của nó được đồng bộ với cơ sở dữ liệu khi mà ta commit cái Session.

  • Detached (Đã bị tách riêng ra): Đối tượng đã từng có trạng thái persistent nhưng hiện tại đã không còn giữ quan hệ với Session. Nếu nó không được attached trở lại, nó sẽ bị bộ gom rác của Java quét đi theo cơ chế thông thường. Một đối tượng đang trong session muốn đạt đươc trạng thái này thì có những cách là gọi hàm evict(), close Session hoặc làm combo thao tác: serialize/deserialize.

  • Removed (Đã bị xóa): tương tự 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.

Sơ đồ bên dưới minh hoạ các trạng thái này:

  • (1) Transient: Trường hợp bạn tạo mới một đối tượng java từ một Entity, đối tượng đó có tình trạng là Transient. Hibernate không biết về sự tồn tại của nó. Nó nằm ngoài sự quản lý của Hibernate.
  • (2) Persistent: Trường hợp bạn lấy ra đối tượng Entity bằng method get, load hoặc find, bạn có được một đối tượng nó tương ứng với 1 record dưới database. Đối tượng này có trạng thái Persistent. Nó được quản lý bởi Hibernate. Khi đối tượng ở trạng thái persistent, tất cả các thay đổi mà bạn thực hiện đối với đối tượng này sẽ được áp dụng cho các bản ghi và các trường cơ sở dữ liệu tương ứng khi flush session.
  • (3) Transient -> Persistent: Session gọi một trong các method save, saveOrUpdate, persist, merge sẽ đẩy đối tượng Transient vào sự quản lý của Hibernate và đối tượng này chuyển sang trạng thái Persistent. Tùy tình huống nó sẽ insert hoặc update dữ liệu vào DB.
  • (4) Persistent -> Detached: Session gọi evict(..) hoặc clear() để đuổi các đối tượng có trạng thái persistent (bền vững) ra khỏi sự quản lý của Hibernate, giờ các đối tượng này sẽ có trạng thái mới là Detached (Bị tách ra).  Nếu nó không được đính (Attached) trở lại, nó sẽ bị bộ gom rác của Java quét đi theo cơ chế thông thường.
  • (5) Detached -> Persistent: Sử dụng update(..), saveOrUpdate(..), merge(..) sẽ đính trở lại các đối tượng Detached vào lại. Tùy tình huống nó sẽ tạo ra dưới DB câu lệnh update hoặc insert. Các đối tượng sẽ trở về trạng thái Persistent (bền vững).
  • (6) Persistent -> Removed: Session gọi method remove(..), delete(..) để xóa một bản ghi, đối tượng persistent giờ chuyển sang trạng thái Removed (Đã bị xóa).

Thao tác Select, Insert, Update, Delete (CRUD) với Hibernate

Trước khi đi vào chi tiết từng phương thức, các bạn nên nhớ rằng tất cả các phương thức như persist, save, update, merge, saveOrUpdate, remove, … không ngay lập tức thực thi các câu lệnh SQL UPDAT, INSERT hoặc DELETE tương ứng. Việc thực thi câu lệnh SQL thực tế vào cơ sở dữ liệu xảy ra khi commit transaction hoặc flush session.

Các phương thức được đề cập về cơ bản quản lý trạng thái của các thể hiện của thực thể bằng cách chuyển chúng giữa các trạng thái khác nhau theo vòng đời của đối tượng trong Hibernate.

Persistent

Phương thức load()

Dùng để load một đối tượng từ database lên, nó sẽ có trạng thái persistent, throw ObjectNotFoundException nếu id không tồn tại.

  • Chỉ sử dụng method load() khi chắc chắn rằng đối tượng tồn tại trong database.
  • Method load() sẽ ném ra 1 exception nếu đối tượng không tìm thấy trong database.
  • Method load() chỉ trả về 1 đối tượng giả (proxy object) nó chỉ lấy dữ liệu từ database ra khi cần tới.

* Proxy Object là 1 đối tượng giả, nó chỉ có id, các thuộc tính khác không được khởi tạo, ví dụ khi bản để FETCH_TYPE = LAZY khi mapping thì nó cũng chỉ trả về 1 proxy object.

Phương thức get()

Giống load(), tuy nhiên trả về null nếu không tồn tại.

  • Nếu không chắc chắn rằng đối tượng có tồn tại trong database không thì hãy dùng get().
  • Method get() sẽ trả về null nếu không tìm thấy đối tượng trong database.
  • Method get() sẽ truy xuất vào database ngay lập tức để lấy đối tượng thực đang tồn tại.

Phương thức find()

Cách thức hoạt động tương tự như get(). Sự khác biệt giữa find() và get() là:

  • find() là một đặc tả của JPA, get() là đặc tả riêng của Hibernate.
  • Một điểm khác biệt nữa về mặt ngữ nghĩa sử dụng: find() có thể có kết quả hoặc không, get() sẽ luôn trả về một vài thứ gì đó thậm chí là null.

Ví dụ

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    System.out.println("- Loading user 1");
    User user1 = session.load(User.class, 1L);
    System.out.println("- After called ");
    System.out.println("- Fullname of user 1 " + user1.getFullname());
    System.out.println("---");
    System.out.println("- Getting user 2");
    User user2 = session.get(User.class, 2L);
    System.out.println("- After called ");
    System.out.println("- Fullname of user 2 " + user2.getFullname());
    System.out.println("---");
    System.out.println("- Finding user 3");
    User user3 = session.find(User.class, 3L);
    System.out.println("- After called ");
    System.out.println("- Fullname of user 3 " + user3.getFullname());
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- Loading user 1
- After called
Hibernate: select user0_.id as id1_3_0_, user0_.created_at as created_2_3_0_, user0_.fullname as fullname3_3_0_, user0_.modified_at as modified4_3_0_, user0_.password as password5_3_0_, user0_.username as username6_3_0_ from user user0_ where user0_.id=?
- Fullname of user 1 Changed 2nd
---
- Getting user 2
Hibernate: select user0_.id as id1_3_0_, user0_.created_at as created_2_3_0_, user0_.fullname as fullname3_3_0_, user0_.modified_at as modified4_3_0_, user0_.password as password5_3_0_, user0_.username as username6_3_0_ from user user0_ where user0_.id=?
- After called
- Fullname of user 2 Hibernate Example
---
- Finding user 3
Hibernate: select user0_.id as id1_3_0_, user0_.created_at as created_2_3_0_, user0_.fullname as fullname3_3_0_, user0_.modified_at as modified4_3_0_, user0_.password as password5_3_0_, user0_.username as username6_3_0_ from user user0_ where user0_.id=?
- After called
- Fullname of user 3 Hibernate Example

Như bạn thấy, thời điểm thực thi SQL của get() và load() là khác nhau. Load() chỉ gọi SQL khi cần sử dụng, SQL được thực thi ngay khi hàm get() và find() được call.

Xem ví dụ về cách xử lý khi không tìm thấy data trong cơ sở dữ liệu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    try {
        System.out.println("- Loading user 1");
        User user1 = session.load(User.class, 1L);
        System.out.println("- After called ");
        System.out.println("- Fullname of user 1 " + user1.getFullname());
    } catch(ObjectNotFoundException e) {
        System.out.println("Could not found user with id = 1");
    }
    System.out.println("---");
    System.out.println("- Getting user 2");
    User user2 = session.get(User.class, 2L);
    System.out.println("- After called ");
    System.out.println("- User 2 is null = " + (user2 == null));
    System.out.println("---");
    System.out.println("- Finding user 3");
    User user3 = session.find(User.class, 3L);
    System.out.println("- After called ");
    System.out.println("- User 3 is null = " + (user3 == null));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
- Loading user 1
- After called
Hibernate: select user0_.id as id1_3_0_, user0_.created_at as created_2_3_0_, user0_.fullname as fullname3_3_0_, user0_.modified_at as modified4_3_0_, user0_.password as password5_3_0_, user0_.username as username6_3_0_ from user user0_ where user0_.id=?
Could not found user with id = 1
---
- Loading user 2
Hibernate: select user0_.id as id1_3_0_, user0_.created_at as created_2_3_0_, user0_.fullname as fullname3_3_0_, user0_.modified_at as modified4_3_0_, user0_.password as password5_3_0_, user0_.username as username6_3_0_ from user user0_ where user0_.id=?
- After called
- User 2 is null = true
---
- Finding user 3
Hibernate: select user0_.id as id1_3_0_, user0_.created_at as created_2_3_0_, user0_.fullname as fullname3_3_0_, user0_.modified_at as modified4_3_0_, user0_.password as password5_3_0_, user0_.username as username6_3_0_ from user user0_ where user0_.id=?
- After called
- User 3 is null = true

Như bạn thấy, load() sẽ throw 1 exception khi không tìm thấy dữ liệu, get() và find() sẽ return về một giá trị null khi không tìm thấy dữ liệu.

Nên sử dụng phương thức nào?

Phương thức get()/ find() thực thi SQL để lấy data ngay khi được gọi, trong khi phương thức load() trả về một proxy object, câu lệnh SQL thực sự chỉ được thực thi cần thiết. Vì vậy load() tốt hơn về performance bởi vì nó hỗ trợ lazy loading.

Phương thức load() sẽ throw exception khi không tìm thấy dữ liệu, vì vậy chúng ta chỉ sử dụng khi đã biết dữ liệu chắc chắn tồn tại.

Phương thức get()/ find() được sử dụng khi ta muốn make sure dữ liệu tồn tại trong database.

Transient –> Persistent

Phương thức persist()

Phương thức persist được thiết kế để thêm một thể hiện mới của thực thể vào persistent context, tức là chuyển một thể hiện từ trạng thái Transient sang trạng thái Persistent. Sau khi gọi persit(), đối tượng bây giờ trong persistence context, nhưng chưa được lưu vào cơ sở dữ liệu. Việc tạo ra các câu lệnh SQL INSERT sẽ chỉ xảy ra khi commit transaction, flush hoặc close session.

Ta thường sử dụng persit() khi ta muốn thêm một bản ghi vào cơ sở dữ liệu. Persit() hoạt động trên đối tượng được truyền “tại chỗ”, thay đổi trạng thái của chính nó và tham chiếu đến đối tượng tồn tại thực tế.

1
2
3
Category cat = new Category();
cat.setName("Java");
session.persist(cat); // void

Phương thức save()

Phương thức save() là original Hibernate API, nó không thuộc đặc tả JPA. Mục đích của nó về cơ bản giống như persist(), nhưng implementation details của nó thì khác. Phương thức này sẽ tạo ra một định danh, đảm bảo rằng nó sẽ return the Serializable của định danh này.

1
2
3
4
5
6
7
8
Category cat = new Category();
cat.setName("Java");
Long id = (Long) session.save(cat);
System.out.println("Cat id = " + id); // 5
Long id2 = (Long) session.save(cat);
System.out.println("Cat id = " + id2); // 5

Hiệu quả của việc lưu một persisted instance là giống như với persist. Sự khác biệt xuất hiện khi ta cố gắng lưu một detached instance:

1
2
3
4
5
6
7
8
9
10
Category cat = new Category();
cat.setName("Java");
Long id = (Long) session.save(cat);
System.out.println("Cat id = " + id); // 6
session.evict(cat);
Long id2 = (Long) session.save(cat);
System.out.println("Cat id = " + id2); // 7

Như bạn thấy, sau khi gọi evict():

  • Id được save lần đầu khác với id được save lần sau.
  • Khi save trên một detached instance sẽ tạo ra một persistent instance mới và gán nó cho một định danh mới. Kết quả là bị duplicate bản ghi trong database khi commit hoặc flush.

Phương thức merge()

Mục đích chính của phương thức merge() là update một persistent entity instance với các giá trị mới từ một detached entity instance.

Phương thức này hoạt động như sau:

  • Tìm một entity instance bằng id lấy từ đối tượng được truyền (hoặc một existing entity instance từ persistence context được lấy ra, hoặc một new instance được load ra từ database).
  • Sao chép các trường từ đối tượng được truyền vào instance vừa tìm được.
  • returns instance mới đã được update, đối tượng trả về có trạng thái persistence, còn đối tượng ban đầu vẫn sẽ không bị quản lý bởi session.

Trong ví dụ sau, ta evict (detach) thực thể đã lưu khỏi context, thay đổi name field, và sau đó merge với detached entity.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setName("Java");
    Long id = (Long) session.save(cat);
    System.out.println("saved object is managed by hibernate session = " + session.contains(cat));
    session.evict(cat);
    System.out.println("evicted object is managed by hibernate session = " + session.contains(cat));
    cat.setName("Hibernate");
    Category cat2 = (Category) session.merge(cat);
    System.out.println("merged object is managed by hibernate session = " + session.contains(cat2));
    System.out.println("Saved object is equals with merged object = " + (cat == cat2));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
6
7
Hibernate: insert into Category (name) values (?)
saved object is managed by hibernate session = true
Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?
evicted object is managed by hibernate session = false
merged object is managed by hibernate session = true
Saved object is equals with merged object = false
Hibernate: update Category set name=? where id=?

Lưu ý rằng phương thức merge trả về một đối tượng – nó là đối tượng được merge, được load vào persistent context và được update, không phải đối tượng category mà ta đã truyền làm đối số. Đó là hai đối tượng khác nhau, và đối tượng category thường cần phải được loại bỏ sau đó.

Như với phương thức persist(), phương thức merge() được chỉ định bởi JSR-220 để có một số ngữ nghĩa nhất định mà bạn có thể dựa vào:

  • Nếu thực thể là detached, nó được sao chép trên một existing persistent entity.
  • Nếu thực thể là transient, nó được sao chép trên một newly created persistent entity.
  • Hoạt động cascades cho tất cả các mối quan hệ : cascade = MERGE hoặc cascade = ALL.

Phương thức update()

Tương tự như với persist() và save(), phương thức update() là một “original” Hibernate API method đã tồn tại trước khi phương thức merge được thêm vào. Ngữ nghĩa của nó khác nhau ở một số điểm chính:

  • Nó hoạt động khi đối tượng được truyền là một persistence entity hoặc detached entity.
  • Phương thức này chuyển đổi đối tượng được truyền từ trạng thái detached thành trạng thái persistent.
  • Phương thức này ném một ngoại lệ nếu ta truyền vào nó một transient entity.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setName("Java");
    session.save(cat);
    System.out.println("saved object is managed by hibernate session = " + session.contains(cat));
    session.evict(cat);
    System.out.println("evicted object is managed by hibernate session = " + session.contains(cat));
    cat.setName("Hibernate");
    session.update(cat);
    System.out.println("updated object is managed by hibernate session = " + session.contains(cat));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
Hibernate: insert into Category (name) values (?)
saved object is managed by hibernate session = true
evicted object is managed by hibernate session = false
updated object is managed by hibernate session = true
Hibernate: update Category set name=? where id=?

Cố gắng thực hiện update trên một transient instance sẽ dẫn đến một ngoại lệ TransientObjectException. Điều sau đây sẽ không hoạt động:

1
2
3
Category cat = new Category();
cat.setName("Java");
session.update(cat); // TransientObjectException

Phương thức SaveOrUpdate()

Phương thức này chỉ xuất hiện trong Hibernate API. Tương tự như update(), nó cũng có thể được sử dụng cho các trường hợp attached lại. Sự khác biệt chính của phương thức update() và saveOrUpdate() là nó không ném ngoại lệ khi được áp dụng cho một transient instance.

Phương thức này hoạt động như sau: nếu là đối tượng mới thì save xuống database, nếu không thì update xuống database. Nó sẽ thực hiện SELECT để kiểm tra trước khi save hoặc update.

  • Nếu  đối tượng đã tồn tại trong session thì nó không làm gì cả.
  • Nếu tồn tại 1 đối tượng khác trong cùng session mà có cùng id thì sẽ xảy ra exception.
  • Nếu đối tượng tượng không có id (chưa tồn tại) thì sẽ thực hiện save().
  • Nếu đối tượng có id nhưng id đó chưa có trong database thì thực hiện save().
  • Các trường hợp còn lại thực hiện update().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setName("Java");
    session.saveOrUpdate(cat);
    System.out.println("saved object is managed by hibernate session = " + session.contains(cat));
    session.evict(cat);
    System.out.println("evicted object is managed by hibernate session = " + session.contains(cat));
    cat.setName("Hibernate");
    session.saveOrUpdate(cat);
    System.out.println("updated object is managed by hibernate session = " + session.contains(cat));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
Hibernate: insert into Category (name) values (?)
saved object is managed by hibernate session = true
evicted object is managed by hibernate session = false
updated object is managed by hibernate session = true
Hibernate: update Category set name=? where id=?

Như bạn thấy phương thức này là một công cụ phổ biến để làm cho một đối tượng persistent bất kể trạng thái của nó là transient hay detached.

Bây giờ hãy xem trường hợp một đối tượng bị giữ bởi 2 session, khi đó phương thức saveOrUpdate() sẽ throw ra một ngoại lệ.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setId(20L);
    cat.setName("Java");
    session.saveOrUpdate(cat);
    Category cat2 = new Category();
    cat2.setId(20L);
    cat2.setName("Java");
    session.saveOrUpdate(cat2);
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Khi chạy chương trình trên, chúng ta sẽ gặp một excepion NonUniqueObjectException. Lý do là có 2 đối tượng cùng được quản lý trong một session.

1
Exception in thread "main" org.hibernate.NonUniqueObjectException: A different object with the same identifier value was already associated with the session : [com.gpcoder.entities.Category#20]

Nên sử dụng phương thức nào?

Nếu không có bất kỳ yêu cầu đặc biệt nào, theo quy tắc chung, ta nên tuân thủ các phương thức persist() và merge(), vì chúng được chuẩn hóa và được đảm bảo để tuân theo đặc tả JPA. Nó sẽ dễ dàng hơn trong trường hợp ta quyết định chuyển sang một persistence provider khác, chẳng hạn iBatis, Eclipse Link, OpenJPA, … Tuy nhiên, một số trường hợp đặc biệt các phương thức Hibernate “gốc” như save(), update() và saveOrUpdate() sẽ hữu dụng hơn nhiều.

Persistent –> Detached

Phương thức evict()

Tách một đối tượng ra khỏi session, biến nó từ trạng thái persistent thành detached.

Các bạn có thể xem lại các ví dụ trên để thấy được cách sử dụng evict().

Phương thức clear()

Tách tất cả đối tượng ra khỏi session, biến tất cả chúng từ trạng thái persistent thành detached.

Ví dụ:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setName("Java");
    session.saveOrUpdate(cat);
    Category cat2 = new Category();
    cat2.setName("Hibernate");
    session.saveOrUpdate(cat2);
    System.out.println("cat1 is managed by hibernate session = " + session.contains(cat));
    System.out.println("cat2 is managed by hibernate session = " + session.contains(cat2));
    session.clear();
    System.out.println("After clear session");
    System.out.println("cat1 is managed by hibernate session = " + session.contains(cat));
    System.out.println("cat2 is managed by hibernate session = " + session.contains(cat2));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
6
7
Hibernate: insert into Category (name) values (?)
Hibernate: insert into Category (name) values (?)
cat1 is managed by hibernate session = true
cat2 is managed by hibernate session = true
After clear session
cat1 is managed by hibernate session = false
cat2 is managed by hibernate session = false

Detached –> Persistent

Phương thức refresh()

Refresh một đối tượng đang ở trạng thái persistent.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setName("Java");
    session.saveOrUpdate(cat);
    System.out.println("saved object is managed by hibernate session = " + session.contains(cat));
    session.evict(cat);
    System.out.println("evicted object is managed by hibernate session = " + session.contains(cat));
    session.refresh(cat);
    System.out.println("refreshed object is managed by hibernate session = " + session.contains(cat));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
5
Hibernate: insert into Category (name) values (?)
saved object is managed by hibernate session = true
evicted object is managed by hibernate session = false
Hibernate: select category0_.id as id1_0_0_, category0_.name as name2_0_0_ from Category category0_ where category0_.id=?
refreshed object is managed by hibernate session = true

Persistent –> Removed

Phương thức delete()

Phương thức này không nằm trong đặc tả JPA, nó là một original hibernate.

Chúng ta cần load đối tượng lên và xoá nó đi thông qua phương thức delete().

Nếu không muốn load lên thì dùng session.createQuery(“DELETE FROM user WHERE …”).executeUpdate();

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
try (Session session = HibernateUtils.getSessionFactory().openSession();) {
    // Begin a unit of work
    session.beginTransaction();
    Category cat = new Category();
    cat.setName("Java");
    session.save(cat);
    System.out.println("saved object is managed by hibernate session = " + session.contains(cat));
    session.delete(cat);
    System.out.println("deleted object is managed by hibernate session = " + session.contains(cat));
    // Commit the current resource transaction, writing any unflushed changes to the database.
    session.getTransaction().commit();
}

Log:

1
2
3
4
Hibernate: insert into Category (name) values (?)
saved object is managed by hibernate session = true
deleted object is managed by hibernate session = false
Hibernate: delete from Category where id=?

Phương thức remove()

Phương thức này nằm trong đặc tả JPA, và hoạt động tương tự như delete().

Tài liệu tham khảo:

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

Có thể bạn quan tâm:

Xem thêm Việc làm IT hấp dẫn trên TopDev