简体   繁体   中英

Spring Boot. @Transactional method calling a @Transactional(readonly=true) method

I have the next problem. When a controller invokes a service method with @Transactional annotation and this method invokes a @Transactional(readonly=true) method, the changes in the object doesn't get saved in the database. I don't know why. I thought that the first method begins a 'read and write' transaction and the second method uses the same transaction.

Example :


/** Controller class **/

@RestController
@RequestMapping("/path1")
public class MyObjectRestController {

    ... 

    @Autowired
    MyObjectService myObjectService;

    @PostMapping(value = "/path2")
    @ResponseStatus(HttpStatus.CREATED) 
    public void save(@RequestBody MyObject myObject) {
        myObjectService.save(myObject);
    }
    
    ...
}
/** Service class **/

public interface MyObjectService {
    public MyObject save(MyObject myObject);
    public MyObject findOne(long id);
}
/** Service implementation class **/

@Service
public class MyObjectServiceImpl implements MyObjectService {

    /**
     * Save Object
     */
    @Override
    @Transactional  
    public Object save(Object newObject) {

        Object myObject = this.findOne(newObject.getId());
        
        // Modify Object
        myObject.setAttribute1(...)
        myObject.setAttribute2(...)
        
        // Save Object (using Repository)
        return MyObjectDao.save(myObject);
    }

    /**
     * Get Object by Id 
     */
    @Override
    @Transactional(readOnly = true)
    public MyObject findOne(long id) {
        Optional<MyObject> myObject = MyObjectDao.findById(id);
        return myObject.isPresent() ? myObject.get() : null;
    }   
}

This example doesn't update the object attributes. But if I remove the @Transactional annotation in save(..) method ... this example works successfully! (the object is modified).

Why is this happening?

I see save method is annotated with @Transactional and calls findOne method which is also @Transactional . So in this case the same transaction is getting propagated to findOne method and it applies readonly behaviour to the current transaction. And thus it does not perform Flush and you see entity is not modified.

So in this case, you should use a separate transaction for read and writes.

findOne method can be annotated with below -

@Transactional(propagation = Propagation.REQUIRES_NEW, readOnly = true)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM