Objek Objek dalam Sesi Hibernate

1. Pengenalan

Hibernate adalah kerangka yang sesuai untuk menguruskan data yang berterusan, tetapi kadang-kadang memahami bagaimana ia berfungsi secara dalaman boleh menjadi sukar.

Dalam tutorial ini, kita akan belajar mengenai keadaan objek dan cara bergerak di antara keduanya. Kami juga akan melihat masalah yang dapat kita hadapi dengan entiti yang terpisah dan cara menyelesaikannya.

2. Sesi Hibernate

Antara muka Sesi adalah alat utama yang digunakan untuk berkomunikasi dengan Hibernate. Ini menyediakan API yang memungkinkan kita membuat, membaca, mengemas kini, dan menghapus objek yang berterusan. The sesi mempunyai kitaran hidup yang mudah. Kami membukanya, melakukan beberapa operasi, dan kemudian menutupnya.

Apabila kita beroperasi pada objek semasa sesi , mereka melekat pada sesi tersebut . Perubahan yang kita buat dikesan dan disimpan semasa ditutup. Setelah ditutup, Hibernate memutuskan hubungan antara objek dan sesi.

3. Keadaan Objek

Dalam konteks Sesi Hibernate , objek dapat berada di salah satu dari tiga keadaan yang mungkin: sementara, berterusan, atau terpisah.

3.1. Sementara

Objek yang belum kami lampirkan pada sesi apa pun adalah dalam keadaan sementara. Oleh kerana tidak pernah berlaku, tidak ada representasi dalam pangkalan data. Kerana tidak ada sesi yang menyadarinya, sesi tersebut tidak akan disimpan secara automatik.

Mari buat objek pengguna dengan konstruktor dan sahkan bahawa ia tidak dikendalikan oleh sesi:

Session session = openSession(); UserEntity userEntity = new UserEntity("John"); assertThat(session.contains(userEntity)).isFalse();

3.2. Berterusan

Objek yang kami kaitkan dengan sesi berada dalam keadaan berterusan. Kami menyimpannya atau membacanya dari konteks kegigihan, sehingga mewakili beberapa baris dalam pangkalan data.

Mari kita mencipta objek dan kemudian gunakan berterusan kaedah untuk membuat ia berterusan:

Session session = openSession(); UserEntity userEntity = new UserEntity("John"); session.persist(userEntity); assertThat(session.contains(userEntity)).isTrue();

Sebagai alternatif, kami mungkin menggunakan kaedah simpan . Perbezaannya adalah bahawa kaedah gigih hanya akan menyimpan objek, dan kaedah simpan juga akan menghasilkan pengecamnya jika diperlukan.

3.3. Terpisah

Semasa kita menutup sesi , semua objek di dalamnya menjadi terpisah. Walaupun mereka masih mewakili baris dalam pangkalan data, mereka tidak lagi dikendalikan oleh sesi apa pun :

session.persist(userEntity); session.close(); assertThat(session.isOpen()).isFalse(); assertThatThrownBy(() -> session.contains(userEntity));

Seterusnya, kita akan belajar bagaimana menyelamatkan entiti sementara dan terpisah.

4. Menyimpan dan Melampirkan Entiti

4.1. Menyimpan Entiti Sementara

Mari buat entiti baru dan simpan ke pangkalan data. Semasa pertama kali kita membina objek, ia akan berada dalam keadaan sementara.

Untuk mengekalkan entiti baru kami, kami akan menggunakan kaedah bertahan :

UserEntity userEntity = new UserEntity("John"); session.persist(userEntity);

Sekarang, kami akan membuat objek lain dengan pengecam yang sama dengan yang pertama. Ini objek kedua adalah fana kerana ia tidak lagi diuruskan oleh mana-mana sesi , tetapi kita tidak boleh membuat ia berterusan menggunakan berterusan kaedah. Itu sudah terwakili dalam pangkalan data, jadi itu tidak benar-benar baru dalam konteks lapisan kegigihan.

Sebagai gantinya, kami akan menggunakan kaedah penggabungan untuk mengemas kini pangkalan data dan menjadikan objek berterusan :

UserEntity onceAgainJohn = new UserEntity("John"); session.merge(onceAgainJohn);

4.2. Menyimpan Entiti Terasing

If we close the previous session, our objects will be in a detached state. Similarly to the previous example, they're represented in the database but they aren't currently managed by any session. We can make them persistent again using the merge method:

UserEntity userEntity = new UserEntity("John"); session.persist(userEntity); session.close(); session.merge(userEntity);

5. Nested Entities

Things get more complicated when we consider nested entities. Let's say our user entity will also store information about his manager:

public class UserEntity { @Id private String name; @ManyToOne private UserEntity manager; }

When we save this entity, we need to think not only about the state of the entity itself but also about the state of the nested entity. Let's create a persistent user entity and then set its manager:

UserEntity userEntity = new UserEntity("John"); session.persist(userEntity); UserEntity manager = new UserEntity("Adam"); userEntity.setManager(manager);

If we try to update it now, we'll get an exception:

assertThatThrownBy(() -> { session.saveOrUpdate(userEntity); transaction.commit(); });
java.lang.IllegalStateException: org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing : com.baeldung.states.UserEntity.manager -> com.baeldung.states.UserEntity 

That's happening because Hibernate doesn't know what to do with the transient nested entity.

5.1. Persisting Nested Entities

One way to solve this problem is to explicitly persist nested entities:

UserEntity manager = new UserEntity("Adam"); session.persist(manager); userEntity.setManager(manager);

Then, after committing the transaction, we'll be able to retrieve the correctly saved entity:

transaction.commit(); session.close(); Session otherSession = openSession(); UserEntity savedUser = otherSession.get(UserEntity.class, "John"); assertThat(savedUser.getManager().getName()).isEqualTo("Adam");

5.2. Cascading Operations

Transient nested entities can be persisted automatically if we configure the relationship's cascade property correctly in the entity class:

@ManyToOne(cascade = CascadeType.PERSIST) private UserEntity manager;

Now when we persist the object, that operation will be cascaded to all nested entities:

UserEntityWithCascade userEntity = new UserEntityWithCascade("John"); session.persist(userEntity); UserEntityWithCascade manager = new UserEntityWithCascade("Adam"); userEntity.setManager(manager); // add transient manager to persistent user session.saveOrUpdate(userEntity); transaction.commit(); session.close(); Session otherSession = openSession(); UserEntityWithCascade savedUser = otherSession.get(UserEntityWithCascade.class, "John"); assertThat(savedUser.getManager().getName()).isEqualTo("Adam");

6. Summary

In this tutorial, we took a closer look at how the Hibernate Session works with respect to object state. We then inspected some problems it can create and how to solve them.

As always, the source code is available over on GitHub.