Hibernate Lifecycle

Công Nghệ
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.

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 Station D

Bài viết liên quan

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bài viết được sự cho phép của tác giả Chung Nguyễn Hôm nay, nhóm Laravel đã phát hành một phiên bản chính mới của “ laravel/installer ” bao gồm hỗ trợ khởi động nhanh các dự án Jetstream. Với phiên bản mới này khi bạn chạy laravel new project-name , bạn sẽ nhận được các tùy chọn Jetstream. Ví dụ: API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth Cách sử dụng Laravel với Socket.IO laravel new foo --jet --dev Sau đó, nó sẽ hỏi bạn thích stack Jetstream nào hơn: Which Jetstream stack do you prefer? [0] Livewire [1] inertia > livewire Will your application use teams? (yes/no) [no]: ... Nếu bạn đã cài bộ Laravel Installer, để nâng cấp lên phiên bản mới bạn chạy lệnh: composer global update Một số trường hợp cập nhật bị thất bại, bạn hãy thử, gỡ đi và cài đặt lại nha composer global remove laravel/installer composer global require laravel/installer Bài viết gốc được đăng tải tại chungnguyen.xyz Có thể bạn quan tâm: Cài đặt Laravel Làm thế nào để chạy Sql Server Installation Center sau khi đã cài đặt xong Sql Server? Quản lý các Laravel route gọn hơn và dễ dàng hơn Xem thêm Tuyển dụng lập trình Laravel hấp dẫn trên Station D

By stationd
Principle thiết kế của các sản phẩm nổi tiếng

Principle thiết kế của các sản phẩm nổi tiếng

Tác giả: Lưu Bình An Phù hợp cho các bạn thiết kế nào ko muốn làm code dạo, design dạo nữa, bạn muốn cái gì đó cao hơn ở tầng khái niệm Nếu lập trình chúng ta có các nguyên tắc chung khi viết code như KISS , DRY , thì trong thiết kế cũng có những nguyên tắc chính khi làm việc. Những nguyên tắc này sẽ là kim chỉ nam, nếu có tranh cãi giữa các member trong team, thì cứ đè nguyên tắc này ra mà giải quyết (nghe hơi có mùi cứng nhắc, mình thì thích tùy cơ ứng biến hơn) Tìm các vị trí tuyển dụng designer lương cao cho bạn Nguyên tắc thiết kế của GOV.UK Đây là danh sách của trang GOV.UK Bắt đầu với thứ user cần Làm ít hơn Thiết kế với dữ liệu Làm mọi thứ thật dễ dàng Lặp. Rồi lặp lại lần nữa Dành cho tất cả mọi người Hiểu ngữ cảnh hiện tại Làm dịch vụ digital, không phải làm website Nhất quán, nhưng không hòa tan (phải có chất riêng với thằng khác) Cởi mở, mọi thứ tốt hơn Bao trừu tượng luôn các bạn, trang Gov.uk này cũng có câu tổng quát rất hay Thiết kế tốt là thiết kế có thể sử dụng. Phục vụ cho nhiều đối tượng sử dụng, dễ đọc nhất nhất có thể. Nếu phải từ bỏ đẹp tinh tế – thì cứ bỏ luôn . Chúng ta tạo sản phẩm cho nhu cầu sử dụng, không phải cho người hâm mộ . Chúng ta thiết kế để cả nước sử dụng, không phải những người đã từng sử dụng web. Những người cần dịch vụ của chúng ta nhất là những người đang cảm thấy khó sử dụng dịch...

By stationd
Hiểu về trình duyệt – How browsers work

Hiểu về trình duyệt – How browsers work

Bài viết được sự cho phép của vntesters.com Khi nhìn từ bên ngoài, trình duyệt web giống như một ứng dụng hiển thị những thông tin và tài nguyên từ server lên màn hình người sử dụng, nhưng để làm được công việc hiển thị đó đòi hỏi trình duyệt phải xử lý rất nhiều thông tin và nhiều tầng phía bên dưới. Việc chúng ta (Developers, Testers) tìm hiểu càng sâu tầng bên dưới để nắm được nguyên tắc hoạt động và xử lý của trình duyệt sẽ rất hữu ích trong công việc viết code, sử dụng các tài nguyên cũng như kiểm thử ứng dụng của mình. Cách để npm packages chạy trong browser Câu hỏi phỏng vấn mẹo về React: Component hay element được render trong browser? Khi hiểu được cách thức hoạt động của trình duyệt chúng ta có thể trả lời được rất nhiều câu hỏi như: Tại sao cùng một trang web lại hiển thị khác nhau trên hai trình duyệt? Tại sao chức năng này đang chạy tốt trên trình duyệt Firefox nhưng qua trình duyệt khác lại bị lỗi? Làm sao để trang web hiển thị nội dung nhanh và tối ưu hơn một chút?… Hy vọng sau bài này sẽ giúp các bạn có một cái nhìn rõ hơn cũng như giúp ích được trong công việc hiện tại. 1. Cấu trúc của một trình duyệt Trước tiên chúng ta đi qua cấu trúc, thành phần chung và cơ bản nhất của một trình duyệt web hiện đại, nó sẽ gồm các thành phần (tầng) như sau: Thành phần nằm phía trên là những thành phần gần với tương tác của người dùng, càng phía dưới thì càng sâu và nặng về xử lý dữ liệu hơn tương tác. Nhiệm...

By stationd
Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Lĩnh vực EdTech (ứng dụng công nghệ vào các sản phẩm giáo dục) trên toàn cầu hiện nay đã tương đối phong phú với nhiều tên tuổi lớn phân phối đều trên các hạng mục như Broad Online Learning Platforms (nền tảng cung cấp khóa học online đại chúng – tiêu biểu như Coursera, Udemy, KhanAcademy,…) Learning Management Systems (hệ thống quản lý lớp học – tiêu biểu như Schoology, Edmodo, ClassDojo,…) Next-Gen Study Tools (công cụ hỗ trợ học tập – tiểu biểu như Kahoot!, Lumosity, Curriculet,…) Tech Learning (đào tạo công nghệ – tiêu biểu như Udacity, Codecademy, PluralSight,…), Enterprise Learning (đào tạo trong doanh nghiệp – tiêu biểu như Edcast, ExecOnline, Grovo,..),… Hiện nay thị trường EdTech tại Việt Nam đã đón nhận khoảng đầu tư khoảng 55 triệu đô cho lĩnh vực này nhiều đơn vị nước ngoài đang quan tâm mạnh đến thị trường này ngày càng nhiều hơn. Là một trong những xu hướng phát triển tốt, và có doanh nghiệp đã hoạt động khá lâu trong ngành nêu tại infographic như Topica, nhưng EdTech vẫn chỉ đang trong giai đoạn sơ khai tại Việt Nam. Tại Việt Nam, hệ sinh thái EdTech trong nước vẫn còn rất non trẻ và thiếu vắng nhiều tên tuổi trong các hạng mục như Enterprise Learning (mới chỉ có MANA), School Administration (hệ thống quản lý trường học) hay Search (tìm kiếm, so sánh trường và khóa học),… Với chỉ dưới 5% số dân công sở có sử dụng một trong các dịch vụ giáo dục online, EdTech cho thấy vẫn còn một thị trường rộng lớn đang chờ được khai phá. *** Vừa qua Station D đã công bố Báo cáo Vietnam IT Landscape 2019 đem đến cái nhìn toàn cảnh về các ứng dụng công...

By stationd