Ralat TransactionRequiredException

1. Gambaran keseluruhan

Dalam tutorial ini, kita akan mengkaji penyebab ralat TransactionRequiredException dan cara menyelesaikannya.

2. TransactionRequiredException

Kesalahan ini biasanya berlaku ketika kita berusaha melakukan operasi pangkalan data yang mengubah pangkalan data tanpa transaksi .

Contohnya, cuba mengemas kini rekod tanpa transaksi:

Query updateQuery = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3"); updateQuery.setParameter(1, title); updateQuery.setParameter(2, body); updateQuery.setParameter(3, id); updateQuery.executeUpdate();

Akan menimbulkan pengecualian dengan mesej seperti berikut:

... javax.persistence.TransactionRequiredException: Executing an update/delete query at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1586) ...

3. Menyediakan Transaksi

Penyelesaian yang jelas adalah membungkus operasi pengubahsuaian pangkalan data dalam transaksi:

Transaction txn = session.beginTransaction(); Query updateQuery = session.createQuery("UPDATE Post p SET p.title = ?1, p.body = ?2 WHERE p.id = ?3"); updateQuery.setParameter(1, title); updateQuery.setParameter(2, body); updateQuery.setParameter(3, id); updateQuery.executeUpdate(); txn.commit();

Dalam coretan kod di atas, kami memulakan dan melakukan transaksi secara manual. Walaupun dalam persekitaran Spring Boot, kami dapat mencapainya dengan menggunakan anotasi @Transactional .

4. Sokongan Transaksi pada Musim Bunga

Sekiranya kita mahukan kawalan yang lebih halus, kita boleh menggunakan Spring's TransactionTemplate . Kerana ini memungkinkan pengaturcara untuk memicu ketekunan objek segera sebelum meneruskan pelaksanaan kaedah dengan kod.

Sebagai contoh, katakan kita ingin mengemas kini siaran sebelum menghantar pemberitahuan e-mel:

public void update() { entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1") // parameters .executeUpdate(); sendEmail(); }

Menggunakan @Transactional ke kaedah di atas boleh menyebabkan e-mel dihantar walaupun terdapat pengecualian dalam proses kemas kini. Ini kerana transaksi hanya akan dilakukan ketika kaedah keluar dan akan kembali kepada pemanggil.

Oleh itu, mengemas kini catatan dalam TransactionTemplate akan mengelakkan senario ini kerana ia akan melakukan operasi dengan segera:

public void update() { transactionTemplate.execute(transactionStatus -> { entityManager.createQuery("UPDATE Post p SET p.title = ?2, p.body = ?3 WHERE p.id = ?1") // parameters .executeUpdate(); transactionStatus.flush(); return null; }); sendEmail(); }

5. Kesimpulan

Kesimpulannya, secara amnya merupakan amalan yang baik untuk membungkus operasi pangkalan data dalam transaksi. Ini membantu dalam mencegah kerosakan data. Kod sumber lengkap boleh didapati di Github.