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