Problem description

Use Jpa to customize update statements in your code, such as the addAge method below:

@Repository
public interface StudentRepository extends JpaRepository<Student, Integer> {

    @Query(value = "update tb_student set age = age + 1 where 1 = 1 ", nativeQuery = true)
    @Modifying
    void addAge();

}
Copy the code

When executing this method, the following error is reported:

javax.persistence.TransactionRequiredException: Executing an update/delete query at org.hibernate.internal.AbstractSharedSessionContract.checkTransactionNeededForUpdateOperation(AbstractSharedSessionContr Act. Java: 398) ~ [hibernate - core - 5.3.11. Final. Jar: 5.3.11. The Final] the at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1581) ~ [hibernate core - 5.3.11. Final. Jar: 5.3.11. The Final] at org. Springframework. Data. The jpa. Repository. Query. JpaQueryExecution$ModifyingExecutionThe doExecute (JpaQueryExecution. Java: 263) ~ [spring - data - jpa - 2.1.10. The jar: 2.1.10. RELEASE] the at org.springframework.data.jpa.repository.query.JpaQueryExecution.execute(JpaQueryExecution.java:91) ~ [spring - data - jpa - 2.1.10. The jar: 2.1.10. RELEASE]Copy the code

Throw javax.mail. Persistence. TransactionRequiredException: Executing an update/delete query

Cause analysis,

Let’s look at this sentence in the exception

at org.hibernate.query.internal.AbstractProducedQuery.executeUpdate(AbstractProducedQuery.java:1581)
Copy the code

Find the executeUpdate method in AbstractProducedQuery:

public int executeUpdate() throws HibernateException {
    getProducer().checkTransactionNeededForUpdateOperation( "Executing an update/delete query" );
    beforeQuery();
    try {
        return doExecuteUpdate(); } catch ( QueryExecutionRequestException e) { throw new IllegalStateException( e ); } catch( TypeMismatchException e ) { throw new IllegalArgumentException( e ); } catch ( HibernateException e) { throw getExceptionConverter().convert( e ); } finally { afterQuery(); }}Copy the code

Into the first sentence checkTransactionNeededForUpdateOperation method:

default void checkTransactionNeededForUpdateOperation(String exceptionMessage) {
    if(! isTransactionInProgress() ) { throw new TransactionRequiredException( exceptionMessage ); }}Copy the code

Before you can see, the execution of the update statement, JPA will judge whether the current statement in a transaction, if not in the transaction, will throw TransactionRequiredException anomalies.

Problem solving

Based on the above analysis, the solution to this problem is simply to run the code in a transaction. Implement the @Transactional annotation on the addAge method to execute

@Query(value = "update tb_student set age = age + 1 where 1 = 1 ", nativeQuery = true)
@Modifying
@Transactional
void addAge();
Copy the code