Errore di TransactionRequiredException

1. Panoramica

In questo tutorial, esamineremo la causa dell'errore TransactionRequiredException e come risolverlo.

2. TransactionRequiredException

Questo errore si verifica in genere quando si tenta di eseguire un'operazione sul database che modifica il database senza una transazione .

Ad esempio, tentando di aggiornare un record senza una transazione:

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();

Solleverà un'eccezione con un messaggio lungo le seguenti linee:

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

3. Fornire una transazione

La soluzione ovvia è racchiudere qualsiasi operazione di modifica del database in una transazione:

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();

Nello snippet di codice sopra, iniziamo manualmente e eseguiamo il commit della transazione. Sebbene in un ambiente Spring Boot, possiamo ottenere ciò utilizzando l' annotazione @Transactional .

4. Supporto alle transazioni in primavera

Se vogliamo un controllo più dettagliato, possiamo usare TransactionTemplate di Spring . Perché questo consente al programmatore di attivare la persistenza di un oggetto immediatamente prima di procedere con l'esecuzione del codice di un metodo.

Ad esempio, supponiamo di voler aggiornare il post prima di inviare una notifica e-mail:

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

L'applicazione di @Transactional al metodo sopra potrebbe causare l'invio dell'e-mail nonostante un'eccezione nel processo di aggiornamento. Questo perché la transazione verrà salvata solo quando il metodo termina e sta per tornare al chiamante.

Pertanto, l'aggiornamento del post all'interno di un TransactionTemplate impedirà questo scenario poiché eseguirà immediatamente il commit dell'operazione:

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. conclusione

In conclusione, è generalmente una buona pratica racchiudere le operazioni del database in una transazione. Aiuta a prevenire la corruzione dei dati. Il codice sorgente completo è disponibile su Github.