Konteks Ketekunan JPA / Hibernate

1. Gambaran keseluruhan

Penyedia kegigihan seperti Hibernate menggunakan konteks kegigihan untuk menguruskan kitaran hayat entiti dalam aplikasi.

Dalam tutorial ini, kita akan bermula dengan pengenalan konteks kegigihan, kemudian kita akan melihat mengapa ia penting. Akhirnya, kita akan melihat perbezaan antara konteks kegigihan yang diliputi transaksi dan konteks kegigihan yang dilanjutkan dengan contoh.

2. Konteks Kegigihan

Mari kita lihat definisi rasmi Konteks Kegigihan:

Contoh EntityManager dikaitkan dengan konteks kegigihan. Konteks kegigihan adalah sekumpulan keadaan entiti di mana untuk setiap identiti entiti berterusan ada contoh entiti yang unik. Dalam konteks kegigihan, keadaan entiti dan kitaran hayatnya diuruskan. API EntityManager digunakan untuk membuat dan menghapus contoh entiti berterusan, untuk mencari entiti dengan kunci utama mereka, dan untuk membuat pertanyaan mengenai entiti.

Pernyataan di atas mungkin kelihatan agak rumit sekarang, tetapi akan masuk akal ketika kami meneruskan. Konteks kegigihan adalah cache tahap pertama di mana semua entiti diambil dari pangkalan data atau disimpan ke pangkalan data . Ia terletak di antara aplikasi kami dan penyimpanan berterusan.

Konteks kegigihan memantau perubahan yang dibuat menjadi entiti terurus. Sekiranya ada perubahan semasa transaksi, entiti tersebut ditandai sebagai kotor. Apabila transaksi selesai, perubahan ini dialihkan ke penyimpanan tetap.

The EntityManager adalah antara muka yang membolehkan kita berinteraksi dengan konteks kegigihan. Setiap kali kita menggunakan EntityManager , kita sebenarnya berinteraksi dengan konteks kegigihan .

Sekiranya setiap perubahan yang dibuat dalam entiti membuat panggilan ke penyimpanan berterusan, kita dapat membayangkan berapa banyak panggilan yang akan dibuat. Ini akan membawa kepada kesan prestasi kerana panggilan simpanan berterusan mahal.

3. Jenis Konteks Ketekunan

Konteks kegigihan terdapat dalam dua jenis:

  • Konteks kegigihan yang diliputi transaksi
  • Konteks kegigihan yang dilanjutkan

Mari kita perhatikan masing-masing.

3.1 Konteks Kegigihan Skop Transaksi

Konteks ketekunan transaksi terikat pada transaksi. Sebaik sahaja urus niaga selesai, entiti yang ada dalam konteks kegigihan akan dimasukkan ke dalam simpanan berterusan.

Apabila kami melakukan sebarang operasi di dalam transaksi, EntityManager memeriksa konteks kegigihan . Sekiranya ada, maka ia akan digunakan. Jika tidak, ia akan mewujudkan konteks kegigihan.

Jenis konteks ketekunan lalai adalah PersistenceContextType.TRANSACTION . Untuk memberitahu EntityManager menggunakan konteks ketekunan urus niaga, kami hanya memberi penjelasan dengan @PersistenceContext :

@PersistenceContext private EntityManager entityManager;

3.2 Konteks Kegigihan Diperluas

Konteks ketekunan yang diperpanjang dapat merangkumi pelbagai transaksi. Kami boleh mengekalkan entiti tanpa transaksi tetapi tidak dapat mengalihkannya tanpa transaksi.

Untuk memberitahu EntityManager untuk menggunakan konteks kegigihan berpanjangan, kita perlu menerapkan atribut type @PersistenceContext :

@PersistenceContext(type = PersistenceContextType.EXTENDED) private EntityManager entityManager;

Dalam kacang sesi tanpa status, konteks ketekunan yang diperpanjang dalam satu komponen sama sekali tidak menyedari konteks kegigihan komponen lain . Ini berlaku walaupun kedua-duanya berada dalam urus niaga yang sama.

Katakan kita meneruskan beberapa entiti dalam kaedah Komponen A , yang dijalankan dalam transaksi. Kami kemudian memanggil beberapa kaedah Komponen B . Dalam Komponen B Cara kegigihan konteks, kita tidak akan mencari entiti kita berterusan sebelum ini dalam kaedah Komponen A .

4. Contoh Konteks Kegigihan

Sekarang kita sudah cukup tahu mengenai konteks kegigihan, inilah masanya untuk menyelami contohnya. Kami akan membuat kes penggunaan yang berbeza dengan konteks ketekunan transaksi dan konteks ketekunan yang diperpanjang.

Pertama, mari buat kelas perkhidmatan kami, TransctionPersistenceContextUserService :

@Component public class TransctionPersistenceContextUserService { @PersistenceContext private EntityManager entityManager; @Transactional public User insertWithTransaction(User user) { entityManager.persist(user); return user; } public User insertWithoutTransaction(User user) { entityManager.persist(user); return user; } public User find(long id) { return entityManager.find(User.class, id); } }

Kelas seterusnya, ExtendedPersistenceContextUserService , sangat serupa dengan perkara di atas, kecuali untuk anotasi @PersistenceContext . Kali ini kami meneruskan PersistenceContextType.EXTENDED ke dalam parameter jenis anotasi @PersistenceContextnya :

@Component public class ExtendedPersistenceContextUserService { @PersistenceContext(type = PersistenceContextType.EXTENDED) private EntityManager entityManager; // Remaining code same as above }

5. Kes Ujian

Sekarang kami telah menyediakan kelas perkhidmatan kami, inilah masanya untuk membuat kes penggunaan yang berbeza dengan konteks ketekunan transaksi dan konteks ketekunan yang diperpanjang.

5.1 Menguji Konteks Kegigihan Transaksi

Mari bertahan entiti Pengguna menggunakan konteks kegigihan yang diliputi transaksi. Entiti akan disimpan dalam simpanan berterusan. Kami kemudian mengesahkan dengan membuat panggilan carian menggunakan EntityManager konteks ketekunan diperpanjang kami :

User user = new User(121L, "Devender", "admin"); transctionPersistenceContext.insertWithTransaction(user); User userFromTransctionPersistenceContext = transctionPersistenceContext .find(user.getId()); assertNotNull(userFromTransctionPersistenceContext); User userFromExtendedPersistenceContext = extendedPersistenceContext .find(user.getId()); assertNotNull(userFromExtendedPersistenceContext);

Apabila kita cuba memasukkan entiti Pengguna tanpa transaksi, maka TransactionRequiredException akan dilemparkan:

@Test(expected = TransactionRequiredException.class) public void testThatUserSaveWithoutTransactionThrowException() { User user = new User(122L, "Devender", "admin"); transctionPersistenceContext.insertWithoutTransaction(user); }

5.2 Menguji Konteks Ketekunan Lanjutan

Seterusnya, mari teruskan pengguna dengan konteks ketekunan yang diperpanjang dan tanpa transaksi. The pengguna entiti akan disimpan dalam konteks pengekalan (cache) tetapi tidak dalam simpanan berterusan:

User user = new User(123L, "Devender", "admin"); extendedPersistenceContext.insertWithoutTransaction(user); User userFromExtendedPersistenceContext = extendedPersistenceContext .find(user.getId()); assertNotNull(userFromExtendedPersistenceContext); User userFromTransctionPersistenceContext = transctionPersistenceContext .find(user.getId()); assertNull(userFromTransctionPersistenceContext);

Dalam konteks kegigihan untuk setiap identiti entiti berterusan, akan ada contoh entiti yang unik. Sekiranya kita cuba mengekalkan entiti lain dengan pengecam yang sama:

@Test(expected = EntityExistsException.class) public void testThatPersistUserWithSameIdentifierThrowException() { User user1 = new User(126L, "Devender", "admin"); User user2 = new User(126L, "Devender", "admin"); extendedPersistenceContext.insertWithoutTransaction(user1); extendedPersistenceContext.insertWithoutTransaction(user2); }

Kami akan melihat EntityExistsException :

javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session

Konteks ketekunan yang diperpanjang dalam transaksi menyimpan entiti dalam simpanan berterusan pada akhir transaksi:

User user = new User(127L, "Devender", "admin"); extendedPersistenceContext.insertWithTransaction(user); User userFromDB = transctionPersistenceContext.find(user.getId()); assertNotNull(userFromDB);

Konteks ketekunan yang diperpanjang mengalihkan entiti yang disimpan dalam cache ke dalam simpanan berterusan ketika digunakan dalam transaksi . Pertama, kami meneruskan entiti tanpa urus niaga. Seterusnya, kami meneruskan entiti lain dalam transaksi:

User user1 = new User(124L, "Devender", "admin"); extendedPersistenceContext.insertWithoutTransaction(user1); User user2 = new User(125L, "Devender", "admin"); extendedPersistenceContext.insertWithTransaction(user2); User user1FromTransctionPersistenceContext = transctionPersistenceContext .find(user1.getId()); assertNotNull(user1FromTransctionPersistenceContext); User user2FromTransctionPersistenceContext = transctionPersistenceContext .find(user2.getId()); assertNotNull(user2FromTransctionPersistenceContext);

6. Kesimpulannya

Dalam tutorial ini, kami memperoleh pemahaman yang baik mengenai konteks kegigihan.

Pertama, kami melihat konteks ketekunan transaksi, yang ada sepanjang hayat transaksi. Kemudian, kami melihat konteks kegigihan yang diperpanjang, yang dapat merangkumi pelbagai transaksi.

Seperti biasa, contoh kod boleh didapati di GitHub.