Kitaran Hayat Entiti Hibernate

1. Gambaran keseluruhan

Setiap entiti Hibernate secara semula jadi mempunyai kitaran hidup dalam kerangka kerja - sama ada dalam keadaan sementara, dikendalikan, terasing atau dihapus.

Memahami keadaan ini pada tahap konsep dan teknikal adalah mustahak untuk dapat menggunakan Hibernate dengan betul.

Untuk mengetahui tentang pelbagai kaedah Hibernate yang berurusan dengan entiti, lihat salah satu tutorial kami sebelumnya.

2. Kaedah Pembantu

Sepanjang tutorial ini, kami akan menggunakan beberapa kaedah pembantu secara konsisten:

  • HibernateLifecycleUtil.getManagedEntities (sesi) - kami akan menggunakannya untuk mendapatkan semua entiti terurus dari kedai dalaman Sesi
  • DirtyDataInspector.getDirtyEntities () - kita akan menggunakan kaedah ini untuk mendapatkan senarai semua entiti yang ditandai sebagai 'kotor'
  • HibernateLifecycleUtil.queryCount (pertanyaan) - kaedah yang mudah untuk melakukan pertanyaan kiraan (*) terhadap pangkalan data terbenam

Semua kaedah pembantu di atas diimport secara statik untuk lebih mudah dibaca. Anda dapat mengetahui pelaksanaannya dalam projek GitHub yang dihubungkan pada akhir artikel ini.

3. Ini Semua Tentang Konteks Kegigihan

Sebelum memasuki topik kitaran hidup entiti, pertama, kita perlu memahami konteks kegigihan .

Ringkasnya, konteks kegigihan terletak di antara kod pelanggan dan penyimpanan data . Ini adalah kawasan pementasan di mana data berterusan ditukar menjadi entiti, siap dibaca dan diubah oleh kod pelanggan.

Secara teori, konteks kegigihan adalah pelaksanaan corak Unit Kerja. Ini melacak semua data yang dimuat, melacak perubahan data tersebut, dan bertanggung jawab untuk akhirnya menyinkronkan setiap perubahan kembali ke pangkalan data pada akhir transaksi perniagaan.

JPA EntityManager dan Sesi Hibernate adalah pelaksanaan konsep konteks kegigihan . Sepanjang artikel ini, kami akan menggunakan Hibernate Session untuk mewakili konteks kegigihan.

Keadaan kitaran hidup entiti hibernate menerangkan bagaimana entiti itu berkaitan dengan konteks kegigihan , seperti yang akan kita lihat selanjutnya.

4. Entiti Terurus

Entiti terurus adalah representasi dari baris jadual pangkalan data (walaupun baris itu belum ada dalam pangkalan data).

Ini dikendalikan oleh Sesi yang sedang berjalan , dan setiap perubahan yang dibuat akan dilacak dan disebarkan ke pangkalan data secara automatik .

The Sesi memuat beban entiti dari pangkalan data atau semula atase-entiti yang terpisah. Kami akan membincangkan entiti yang terpisah di bahagian 5.

Mari perhatikan beberapa kod untuk mendapatkan penjelasan.

Aplikasi sampel kami menentukan satu entiti, kelas FootballPlayer . Pada permulaan, kami akan memulakan penyimpanan data dengan beberapa contoh data:

+-------------------+-------+ | Name | ID | +-------------------+-------+ | Cristiano Ronaldo | 1 | | Lionel Messi | 2 | | Gianluigi Buffon | 3 | +-------------------+-------+

Katakanlah kita mahu menukar nama Buffon bermula - kita mahu memasukkan nama penuhnya Gianluigi Buffon dan bukannya Gigi Buffon.

Pertama, kita perlu memulakan unit kerja kita dengan mendapatkan Sesi:

Session session = sessionFactory.openSession();

Dalam persekitaran pelayan, kami mungkin memasukkan Sesi ke kod kami melalui proksi yang memahami konteks. Prinsipnya tetap sama: kami memerlukan Sesi untuk merangkumi urus niaga perniagaan unit kerja kami.

Seterusnya, kami akan mengarahkan Sesi kami memuatkan data dari kedai berterusan:

assertThat(getManagedEntities(session)).isEmpty(); List players = s.createQuery("from FootballPlayer").getResultList(); assertThat(getManagedEntities(session)).size().isEqualTo(3); 

Semasa kami pertama kali mendapat Sesi , kedai konteksnya yang berterusan kosong, seperti yang ditunjukkan oleh pernyataan penegasan pertama kami .

Seterusnya, kami menjalankan pertanyaan yang mengambil data dari pangkalan data, membuat representasi entiti data, dan akhirnya mengembalikan entiti untuk kami gunakan.

Secara dalaman, Sesi melacak semua entiti yang dimuatnya di gedung konteks yang berterusan. Dalam kes kami, stor dalaman Sesi akan mengandungi 3 entiti selepas pertanyaan.

Sekarang mari kita menukar nama Gigi:

Transaction transaction = session.getTransaction(); transaction.begin(); FootballPlayer gigiBuffon = players.stream() .filter(p -> p.getId() == 3) .findFirst() .get(); gigiBuffon.setName("Gianluigi Buffon"); transaction.commit(); assertThat(getDirtyEntities()).size().isEqualTo(1); assertThat(getDirtyEntities().get(0).getName()).isEqualTo("Gianluigi Buffon");

4.1. Bagaimanakah ia berfungsi?

Semasa panggilan ke transaksi melakukan () atau flush () , Sesi akan menemui entiti kotor dari senarai penjejakannya dan menyegerakkan keadaan ke pangkalan data.

Perhatikan bahawa kami tidak perlu memanggil kaedah apa pun untuk memberitahu Sesi bahawa kami mengubah sesuatu dalam entiti kami - kerana ia adalah entiti yang dikelola, semua perubahan disebarkan ke pangkalan data secara automatik.

Entiti terurus selalu merupakan entiti berterusan - ia mesti mempunyai pengecam pangkalan data, walaupun perwakilan baris pangkalan data belum dibuat iaitu pernyataan INSERT sedang menunggu akhir unit kerja.

Lihat bab mengenai entiti sementara di bawah.

5. Entiti Terasing

A entiti terpisah hanya satu Pojo entiti biasa yang identitinya nilai sepadan dengan berturut-turut dalam pangkalan data. Perbezaan dari entiti yang diuruskan adalah bahawa ia tidak dikesan lagi oleh konteks kegigihan .

Entiti boleh terpisah ketika Sesi yang digunakan untuk memuatnya ditutup, atau ketika kita memanggil Session.evict (entiti) atau Session.clear () .

Mari lihat dalam kod:

FootballPlayer cr7 = session.get(FootballPlayer.class, 1L); assertThat(getManagedEntities(session)).size().isEqualTo(1); assertThat(getManagedEntities(session).get(0).getId()).isEqualTo(cr7.getId()); session.evict(cr7); assertThat(getManagedEntities(session)).size().isEqualTo(0);

Konteks kegigihan kami tidak akan menjejaki perubahan entiti yang terpisah:

cr7.setName("CR7"); transaction.commit(); assertThat(getDirtyEntities()).isEmpty();

Session.merge (entiti) /Session.update (entiti) boleh (kembali) melampirkan sesi :

FootballPlayer messi = session.get(FootballPlayer.class, 2L); session.evict(messi); messi.setName("Leo Messi"); transaction.commit(); assertThat(getDirtyEntities()).isEmpty(); transaction = startTransaction(session); session.update(messi); transaction.commit(); assertThat(getDirtyEntities()).size().isEqualTo(1); assertThat(getDirtyEntities().get(0).getName()).isEqualTo("Leo Messi");

Untuk rujukan mengenai Session.merge () dan Session.update () lihat di sini.

5.1. Bidang Identiti Itu Penting

Mari lihat logik berikut:

FootballPlayer gigi = new FootballPlayer(); gigi.setId(3); gigi.setName("Gigi the Legend"); session.update(gigi);

Dalam contoh di atas, kami telah membuat entiti dengan cara biasa melalui pembangunnya. Kami telah mengisi bidang dengan nilai dan kami menetapkan identiti menjadi 3, yang sesuai dengan identiti data berterusan milik Gigi Buffon. Panggilan kemas kini () mempunyai kesan yang sama seperti kita telah memuatkan entiti dari konteks kegigihan yang lain .

Sebenarnya, Sesi tidak membezakan asal entiti yang dilampirkan semula.

Ini adalah senario biasa dalam aplikasi web untuk membina entiti yang terpisah dari nilai bentuk HTML.

Sejauh Sesi berkenaan, entiti yang terpisah adalah entiti biasa yang nilai identitinya sesuai dengan data berterusan.

Be aware that the example above just serves a demo purpose. and we need to know exactly what we're doing. Otherwise, we could end up with null values across our entity if we just set the value on the field we want to update, leaving the rest untouched (so, effectively null).

6. Transient Entity

A transient entity is simply an entity object that has no representation in the persistent store and is not managed by any Session.

A typical example of a transient entity would be instantiating a new entity via its constructor.

To make a transient entity persistent, we need to call Session.save(entity) or Session.saveOrUpdate(entity):

FootballPlayer neymar = new FootballPlayer(); neymar.setName("Neymar"); session.save(neymar); assertThat(getManagedEntities(session)).size().isEqualTo(1); assertThat(neymar.getId()).isNotNull(); int count = queryCount("select count(*) from Football_Player where name="Neymar""); assertThat(count).isEqualTo(0); transaction.commit(); count = queryCount("select count(*) from Football_Player where name="Neymar""); assertThat(count).isEqualTo(1);

As soon as we execute Session.save(entity), the entity is assigned an identity value and becomes managed by the Session. However, it might not yet be available in the database as the INSERT operation might be delayed until the end of the unit of work.

7. Deleted Entity

An entity is in a deleted (removed) state if Session.delete(entity) has been called, and the Session has marked the entity for deletion. The DELETE command itself might be issued at the end of the unit of work.

Let's see it in the following code:

session.delete(neymar); assertThat(getManagedEntities(session).get(0).getStatus()).isEqualTo(Status.DELETED);

However, notice that the entity stays in the persistent context store until the end of the unit of work.

8. Conclusion

Konsep konteks kegigihan adalah pusat untuk memahami kitaran hidup entiti Hibernate. Kami telah menjelaskan kitaran hidup dengan melihat contoh kod yang menunjukkan setiap status.

Seperti biasa, kod yang digunakan dalam artikel ini boleh didapati di GitHub.