mvlupan
mvlupan

Reputation: 3646

Spring @Transactional only works if caller is also @Transactional

I am strugelling to understand why are my updates not commited when i try to use a @Scheduled method.
This is a simplification of my scenario:

@Service
public class UserService {

    @Transactional
    public void updateUser(User user){
        user.setName("Doe");
    }
}

This service is called from two locations:

@RestController
@RequestMapping(value = "/users")
public class UserController {

    @Autowired
    private UserService  userService;
    @Autowired
    private UserRepository userRepository;

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(value = "/{id}", method = RequestMethod.PUT)
    public void getAvailableIssuers(@PathVariable("id") String id){
        User user = userRepository.findOne(id);
        userService.updateUser(user);
    }
}

and a service that use a @Scheduled method:

@Component
class InternalService {

    @Autowired
    private UserService  userService;

    @Autowired
    private UserRepository userRepository;

    @Scheduled(fixedRate=1000)
    public void updateUser(){
        User user = userRepository.findOne(1L);
        userService.updateUser(user);
    }
}

My problem is that when I try to update the user through the InternalService the user never gets updated - but it is getting updated perfectly fine through the RestController. When I add the @Transactional annotation for the scheduled method (even with readOnly = true) it works.

I read the documentation from spring regarding transactions but i still don`t understand why is it not working. I checked with the debuger and userService is in the form of a Spring Proxy.

Can someone help me with an explanation for this?

Upvotes: 2

Views: 679

Answers (1)

The problem is that your operation isn't constrained to that service method: In both cases, you're retrieving the object from the repository in the calling method. Your transaction has to cover the entire collection of database operations.

As to why your controller actually is working, I can't say for sure with just this information, but I'd guess that you are using OpenEntityManagerInView and getting a transactional boundary for free.

Upvotes: 1

Related Questions