๐Ÿ”ด The Error You're Seeing

Confirm this matches your console output. If it does, you're in the right place.

ERROR LOGjakarta.persistence.TransactionRequiredException: Executing an update/delete query at org.hibernate.query.sql.internal.NativeQueryImpl.doExecuteUpdate(NativeQueryImpl.java:309) at org.hibernate.query.sql.internal.NativeQueryImpl.executeUpdate(NativeQueryImpl.java:258)

โšก Quick Fix Works 80% of the time

Annotate the test method or repository method with @Transactional.

@Test @Transactional void testUpdateQuery() { repo.updateStatus(1L, "ACTIVE"); }

๐Ÿง  Why this Happens

Tap to expand the deep technical explanation

In a standard `@DataJpaTest`, test methods are `@Transactional` by default and roll back at the end. However, if you call a custom `@Modifying` query, or use the `EntityManager` directly outside of a repository method, Hibernate might execute the query outside of the test's transaction boundary, triggering this error.

The HITEC City Parking Spot Analogy:

It's like trying to sign a legally binding contract during a fire drill. The notary (Hibernate) refuses to stamp the document because you aren't in a secure, formal office environment (Transaction).

๐Ÿ” How to Reproduce Confirm this is your error

Create a `@DataJpaTest`. Inject `EntityManager`. In the test method, run `entityManager.createNativeQuery("UPDATE users SET name='Deva'").executeUpdate();` without adding `@Transactional` to the specific method.

๐Ÿ› ๏ธ Solutions (5 Ways to Fix)

Solution 1โœ“ Most common cause

Add @Transactional to the test method

๐Ÿ‘‰ Use this if your test method directly executes modifying queries.

Ensure the database modification happens inside a transaction so Hibernate can execute it.

@Test @Transactional void testUpdate() { entityManager.createNativeQuery("UPDATE users SET name='Deva'").executeUpdate(); }
Solution 2

Ensure @Modifying is on the repository method

๐Ÿ‘‰ Use this if calling a custom `@Query` from a repository.

Spring Data JPA needs to know the query alters data to wrap it in a transaction automatically.

@Repository public interface UserRepo extends JpaRepository<User, Long> { @Modifying @Transactional @Query("UPDATE User u SET u.status = :status") void updateStatus(@Param("status") String status); }
Solution 3

Flush the EntityManager manually

๐Ÿ‘‰ Use this if you are saving entities and want to force the DB to execute the SQL immediately.

Sometimes the query is pending in the persistence context. Flushing sends it to the DB within the existing transaction.

@Test @Transactional void testSaveAndFlush() { repo.save(new User("Deva")); entityManager.flush(); // Force SQL execution }
Solution 4

Disable Rollback (Commit changes)

๐Ÿ‘‰ Use this if you need the data to persist in the H2 database for subsequent tests in the same class.

By default, `@DataJpaTest` rolls back. If you want the data to stay, you must commit the transaction.

@Test @Transactional @Rollback(false) // or @Commit void testPersistData() { repo.save(new User("Deva")); }
Solution 5

Use TestEntityManager instead of EntityManager

๐Ÿ‘‰ Use this for idiomatic Spring Boot testing.

Spring Boot provides `TestEntityManager`, which handles transactions and flushing gracefully within tests.

@Autowired private TestEntityManager testEntityManager; @Test void test() { testEntityManager.persistAndFlush(new User("Deva")); }

๐Ÿ“‹ Version Notes

Spring Boot 2.x

Uses javax.persistence.TransactionRequiredException.

Spring Boot 3.x

Uses jakarta.persistence.TransactionRequiredException.

๐Ÿ›ก๏ธ How to Prevent This Next Time

Use Spring Boot's `TestEntityManager` for JPA tests instead of the standard `EntityManager`. It is designed to work within test transaction boundaries.

Course Search
Search across all chapters & stages
๐Ÿ“–

Search the course

Type any topic โ€” branching, stash, rebase, hooks โ€” and jump straight to that chapter.

merge branchesgit stashundo commitrebase