spring-projects / spring-data-jpa

Simplifies the development of creating a JPA-based data access layer.
https://spring.io/projects/spring-data-jpa/
Apache License 2.0
3.02k stars 1.42k forks source link

Automatically run default transactions for @Modifying query methods [DATAJPA-1352] #1673

Closed spring-projects-issues closed 6 years ago

spring-projects-issues commented 6 years ago

Maciej Zerkowski opened DATAJPA-1352 and commented

This is a followup on the issue described here.

public interface PersonRepository extends JpaRepository<Person, Long> {
    @Query(value = "TRUNCATE TABLE person", nativeQuery = true)
    @Modifying
    void truncate();
}

@Service
public class PersonService {
    @Autowired
    private OtherService oS;

    public void init() {
        oS.init();
    }
}

@Service
public class OtherService {
    @Autowired
    private PersonRepository dao;

    @Transactional      <----- it does not help (works fine with @Transactional over PersonService.init or over PersonRepository.trancate only)
    public void init() {
        dao.truncate();
    }
}

The same situation appears for inheritance instead of composition


Affects: 1.11.12 (Ingalls SR12)

Reference URL: https://github.com/spring-projects/spring-boot/issues/3576#issuecomment-390199991

spring-projects-issues commented 6 years ago

Oliver Drotbohm commented

The example you present here is significantly altered from what you presented in the Boot tracker. So a couple of remarks:

The discussion at the Boot ticket left of at the point where I was expressing the option to run default transactions for @Modifying queries. We still might consider that but I highly doubt that everything surrounding that core bit is actually broken, as the setup (transactional components delegating to each other) is so ubiquitous and extensively tested in Spring Framework itself.

If the setup you show is really not working, please provide a sample project with a failing test case

spring-projects-issues commented 6 years ago

Maciej Zerkowski commented

Yes it is different - there is no @PostConstruct - it's just a followup on the attached link but the example was changed as described in one of the mentioned comment.

The issue is that @Transactional annotation does not work if put on 'intermediate' service (or super class:  PersonService extends OtherService for instance) - just use attached example and call PersonService.init() method whenever you want. You will get:

Executing an update/delete query; nested exception is javax.persistence.TransactionRequiredException: Executing an update/delete query

I hope it helps

spring-projects-issues commented 6 years ago

Jens Schauder commented

Please provide an executable example, i.e. a project that we can build and execute with Maven or Gradle. The problem is most likely in the setup, which you are not showing at all

spring-projects-issues commented 6 years ago

Maciej Zerkowski commented

Update - it does not work when method is not marked as public, e.g.:

@Service
public class OtherService { 

@Autowired 
private PersonRepository dao; 

@Transactional <----- it does not help (works fine with @Transactional over PersonService.init or over PersonRepository.trancate only) 
void init() { 
   dao.truncate(); 
}

}

 

spring-projects-issues commented 6 years ago

Stéphane Nicoll commented

Maciej Zerkowski can you please look at the documentation of the feature please? @Transactional is only supported on public methods in non AspectJ setup (which is your case)

spring-projects-issues commented 6 years ago

Jens Schauder commented

This is specified behavior. See https://docs.spring.io/spring/docs/current/spring-framework-reference/data-access.html#transaction-declarative-annotations

Method visibility and @Transactional When using proxies, you should apply the @Transactional annotation only to methods with public visibility. If you do annotate protected, private or package-visible methods with the @Transactional annotation, no error is raised, but the annotated method does not exhibit the configured transactional settings. Consider the use of AspectJ (see below) if you need to annotate non-public methods.

spring-projects-issues commented 6 years ago

Maciej Zerkowski commented

Yes, this is what I read. Thanks!