diff --git a/src/main/java/org/springframework/data/jpa/repository/Modifying.java b/src/main/java/org/springframework/data/jpa/repository/Modifying.java index 1085ae88c..48158a7d9 100644 --- a/src/main/java/org/springframework/data/jpa/repository/Modifying.java +++ b/src/main/java/org/springframework/data/jpa/repository/Modifying.java @@ -26,12 +26,20 @@ import java.lang.annotation.Target; * * @author Oliver Gierke * @author Christoph Strobl + * @author Nicolas Cirigliano */ @Retention(RetentionPolicy.RUNTIME) @Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) @Documented public @interface Modifying { + /** + * Defines whether we should flush the underlying persistence context before executing the modifying query. + * + * @return + */ + boolean flushAutomatically() default false; + /** * Defines whether we should clear the underlying persistence context after executing the modifying query. * diff --git a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java index 1db31056f..7b03909e6 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/AbstractJpaQuery.java @@ -52,6 +52,7 @@ import org.springframework.util.Assert; * @author Thomas Darimont * @author Mark Paluch * @author Christoph Strobl + * @author Nicolas Cirigliano * @author Jens Schauder * @author Сергей Цыпанов */ @@ -145,7 +146,7 @@ public abstract class AbstractJpaQuery implements RepositoryQuery { } else if (method.isPageQuery()) { return new PagedExecution(method.getParameters()); } else if (method.isModifyingQuery()) { - return method.getClearAutomatically() ? new ModifyingExecution(method, em) : new ModifyingExecution(method, null); + return new ModifyingExecution(method, em); } else { return new SingleEntityExecution(); } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java index 14f40c761..bb03462c4 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryExecution.java @@ -1,5 +1,5 @@ /* - * Copyright 2008-2017 the original author or authors. + * Copyright 2008-2018 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -54,6 +54,7 @@ import org.springframework.util.ReflectionUtils; * @author Thomas Darimont * @author Mark Paluch * @author Christoph Strobl + * @author Nicolas Cirigliano */ public abstract class JpaQueryExecution { @@ -218,11 +219,14 @@ public abstract class JpaQueryExecution { */ static class ModifyingExecution extends JpaQueryExecution { - private final @Nullable EntityManager em; + private final EntityManager em; + private final boolean flush; + private final boolean clear; /** - * Creates an execution that automatically clears the given {@link EntityManager} after execution if the given - * {@link EntityManager} is not {@literal null}. + * Creates an execution that automatically flushes the given {@link EntityManager} before execution and/or + * clears the given {@link EntityManager} after execution if the given {@link EntityManager} is not + * {@literal null}. * * @param em */ @@ -236,14 +240,20 @@ public abstract class JpaQueryExecution { Assert.isTrue(isInt || isVoid, "Modifying queries can only use void or int/Integer as return type!"); this.em = em; + this.flush = method.getFlushAutomatically(); + this.clear = method.getClearAutomatically(); } @Override protected Object doExecute(AbstractJpaQuery query, Object[] values) { + if (em != null && flush) { + em.flush(); + } + int result = query.createQuery(values).executeUpdate(); - if (em != null) { + if (em != null && clear) { em.clear(); } diff --git a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java index 3a290855e..f83637d7d 100644 --- a/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java +++ b/src/main/java/org/springframework/data/jpa/repository/query/JpaQueryMethod.java @@ -51,6 +51,7 @@ import org.springframework.util.StringUtils; * @author Oliver Gierke * @author Thomas Darimont * @author Christoph Strobl + * @author Nicolas Cirigliano * @author Mark Paluch * @author Сергей Цыпанов */ @@ -312,6 +313,15 @@ public class JpaQueryMethod extends QueryMethod { return StringUtils.hasText(annotatedName) ? annotatedName : getNamedQueryName() + ".count"; } + /** + * Returns whether we should flush automatically for modifying queries. + * + * @return + */ + boolean getFlushAutomatically() { + return getMergedOrDefaultAnnotationValue("flushAutomatically", Modifying.class, Boolean.class); + } + /** * Returns whether we should clear automatically for modifying queries. * diff --git a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java index 03baa5ee5..0a3a50400 100644 --- a/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java +++ b/src/test/java/org/springframework/data/jpa/repository/query/JpaQueryExecutionUnitTests.java @@ -46,6 +46,7 @@ import org.springframework.data.repository.query.Parameters; * @author Oliver Gierke * @author Thomas Darimont * @author Mark Paluch + * @author Nicolas Cirigliano */ @RunWith(MockitoJUnitRunner.Silent.class) public class JpaQueryExecutionUnitTests { @@ -84,16 +85,35 @@ public class JpaQueryExecutionUnitTests { @Test @SuppressWarnings({ "unchecked", "rawtypes" }) - public void modifyingExecutionClearsEntityManagerIfSet() { + public void modifyingExecutionFlushesEntityManagerIfSet() { when(query.executeUpdate()).thenReturn(0); when(method.getReturnType()).thenReturn((Class) void.class); + when(method.getFlushAutomatically()).thenReturn(true); when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query); when(jpaQuery.getQueryMethod()).thenReturn(method); ModifyingExecution execution = new ModifyingExecution(method, em); execution.execute(jpaQuery, new Object[] {}); + verify(em, times(1)).flush(); + verify(em, times(0)).clear(); + } + + @Test + @SuppressWarnings({ "unchecked", "rawtypes" }) + public void modifyingExecutionClearsEntityManagerIfSet() { + + when(query.executeUpdate()).thenReturn(0); + when(method.getReturnType()).thenReturn((Class) void.class); + when(method.getClearAutomatically()).thenReturn(true); + when(jpaQuery.createQuery(Mockito.any(Object[].class))).thenReturn(query); + when(jpaQuery.getQueryMethod()).thenReturn(method); + + ModifyingExecution execution = new ModifyingExecution(method, em); + execution.execute(jpaQuery, new Object[] {}); + + verify(em, times(0)).flush(); verify(em, times(1)).clear(); }