0

I am trying to use Spring retry for my Spring web application (with JPA, hibernate).

Currently, I have a long transaction chain (marked functions as @Transactional) in my application, intuitively:

start transction -> A() -> B() -> C() -> D() - E() -> commit/rollback

now I want to have D() to be retried if any concurrency failure occurred (marked D() with @retryable), but remain A(), B(), C() in current states

I failed, the function D() is not retried at all and just throwed a concurrency failure error (eg. ObjectOptimisticLockingFailureException)

For me, if I want to do such things in database, I have to make a new transaction try catch block with a cursor while loop to handle retries. I wonder is there a simple way I can handle this "partial" transaction retry in Spring?

An example code would be:

@RestController
public DimensionController()
{
    ...
    @Autowired
    private TblDimensionService dimensionService;

    ...
    @PutMapping(...)
    public ResponseEntity<TblDimensionDTO> update(@Valid @RequestBody TblDimensionDTO dimensionDTO)
    {
        ...
        dimensionService.update(dimensionDTO);
        ...
    }
}


@Transactional //transaction in service level
@Service
public TblDimensionService()
{
    ...
    @Autowired
    private RetryService retryService;

    ...
    public TblDimensionDTO update(TblDimensionDTO dimensionDTO) throws InterruptedException
    {
        if (dimensionDTO.getId() == null)
        {
            throw new ResponseStatusException(HttpStatus.NOT_FOUND, "not found");
        }

        TblDimension dimension = findByIdOrElseThrow(dimensionDTO.getId()); //call another function to retrieve entity by id with JPA repository

        dimension = retryService.updateEntity(dimension, dimensionDTO);

        return tblDimensionMapper.toDto(dimension);
    }
    ...
}

@Transactional //transaction in service level
@Service
public RetryService()
{
    ...
    @Autowired
    private TblDimensionRepository dimensionRepository;

    ...
    //I want to only retry this part
    //but this retry does not work
    @Retryable(value = {ConcurrencyFailureException.class})
    public TblDimension updateEntity(TblDimension dimension, TblDimensionDTO dimensionDTO) throws InterruptedException
    {    
        Thread.sleep(3000);

        dimension.setHeight(dimension.getHeight() + 1);

        Thread.sleep(3000);

        return dimensionRepository.save(dimension);
    }
    ...
}
Daniel Hua
  • 153
  • 2
  • 8

0 Answers0