Skip to content

add flushAutomatically attribute to @Modifying annotation [DATAJPA-806] #1167

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
spring-projects-issues opened this issue Sep 27, 2015 · 8 comments
Assignees
Labels
in: core Issues in core support type: enhancement A general enhancement

Comments

@spring-projects-issues
Copy link

Ciri opened DATAJPA-806 and commented

@Modifying annotation has clearAutomatically attribute which defines whether it should clear the underlying persistence context after executing the modifying query.

Code example:

public interface EmailRepository extends JpaRepository<Email, Long> {
    @Transactional
    @Modifying(clearAutomatically = true)
    @Query("update Email e set e.active = false where e.active = true and e.expire <= NOW()")
    Integer deactivateByExpired();
}

When executing modifying queries with this attribute activated, it drops all non-flushed changes still pending in the EntityManager.

To avoid this situation I had to implement a custom repository to manually execute the flush of the EntityManager, then the update query, and finally clear the underlying persistence context:

public interface EmailRepository extends JpaRepository<Email, Long>, EmailRepositoryCustom {
}

public interface EmailRepositoryCustom {
    Integer deactivateByExpired();
}

public class EmailRepositoryImpl implements EmailRepositoryCustom {
    @PersistenceContext
    private EntityManager entityManager;

    @Transactional
    @Override
    public Integer deactivateByExpired() {
        String hsql = "update Email e set e.active = false where e.active = true and e.expire <= NOW()";
        Query query = entityManager.createQuery(hsql);
        entityManager.flush();
        Integer result = query.executeUpdate();
        entityManager.clear();
        return result;
    }
}

Is it possible to add a new attribute to @Modifying annotation called flushAutomatically to automatically flush all non-persisted changes to the underlying context before executing the modifying query?


Affects: 1.9 GA (Gosling)

Reference URL: http://stackoverflow.com/questions/32258857/spring-boot-data-jpa-modifying-update-query-refresh-persistence-context

Backported to: 2.0.4 (Kay SR4), 1.11.11 (Ingalls SR11)

6 votes, 8 watchers

@spring-projects-issues
Copy link
Author

Oliver Drotbohm commented

Shouldn't the execution of a query flush the EntityManager automatically?

@spring-projects-issues
Copy link
Author

Ciri commented

JPA’s AUTO FlushModeType and Hibernate: if the current executed query is not going to hit the pending SQL INSERT/UPDATE/DELETE statements then the flush is not strictly required.

As stated in the reference documentation, the AUTO flush strategy may sometimes synchronize the current persistence context prior to a query execution.

The clearAutomatically property drops all the pending changes in the EntityManager that are not related to the current update query (cause they are not automatically flushed).

That's why I'm asking for a new property to force the EntityManager to flush changes

@spring-projects-issues
Copy link
Author

Ciri commented

Spring Data JPA - Reference Documentation

http://docs.spring.io/spring-data/jpa/docs/current/reference/html/#jpa.modifying-queries

This will trigger the query annotated to the method as updating query instead of a selecting one. As the EntityManager might contain outdated entities after the execution of the modifying query, we do not automatically clear it (see JavaDoc of EntityManager.clear() for details) since this will effectively drop all non-flushed changes still pending in the EntityManager. If you wish the EntityManager to be cleared automatically you can set @Modifying annotation’s clearAutomatically attribute to true.

Hibernate implementation

When an AutoFlushEvent is handled by the DefaultAutoFlushEventListener it checks if a flush is really needed. It can happen that the flush mode is set to FlushMode.ALWAYS (which is not the default value) or that the tables to be updated have pending changes. In both of these cases the auto flush is done before the execution of the query.

org.hibernate.event.internal.DefaultAutoFlushEventListener
private boolean flushIsReallyNeeded(AutoFlushEvent event, final EventSource source) {
    return source.getActionQueue()
            .areTablesToBeUpdated( event.getQuerySpaces() ) ||
                    source.getFlushMode()==FlushMode.ALWAYS;
}

If other tables have pending changes, the flush is not done before the execution of the query and the clear of the EntityManager will discard these changes.

flushAutomatically attribute in @Modifying annotation

The new attribute indicates that the EntityManager will flush all non persisted changes before executing the update.
A new JpaQueryExecution should be implemented with the following logic:

    @Override
    protected Object doExecute(AbstractJpaQuery query, Object[] values) {

        if (em != null) {
            em.flush();
        }

        int result = query.createQuery(values).executeUpdate();

        if (em != null) {
            em.clear();
        }

        return result;
    }

What do you think about this approach?
Regards,
Ciri..

@spring-projects-issues
Copy link
Author

Ciri commented

Created pull-request: #172

@spring-projects-issues
Copy link
Author

Łukasz Glapiński commented

Any updates on this one?

@spring-projects-issues
Copy link
Author

Ciri commented

remote development branch https://github.com/ciri-cuervo/spring-data-jpa/tree/issue/DATAJPA-806
was updated not to have conflicts with master https://github.com/spring-projects/spring-data-jpa/tree/master
in pull request #172

@spring-projects-issues
Copy link
Author

Florian Hopf commented

I can confirm that the workaround with the custom repository solves this issue but is cumbersome.

Are there any plans to incorporate the proposed PR? The current behaviour can be quite surprising to the user

@spring-projects-issues
Copy link
Author

Oliver Drotbohm commented

The PR looks like a decent start and we could go ahead with it. I'd propose the following changes to it:

  • ModifyingExecution should reject null EntityManager instances on construction now

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core support type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

2 participants