最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

spring - @Retryable with a transactional context - Stack Overflow

programmeradmin1浏览0评论

I have an issue when two threads try to create an entity in my database. The first thread checks if the object exists, sees that it is not there, and then creates it. However, at the same time, the second thread also checks if the object exists and, not finding it, tries to create it as well.

I want to solve this issue using @Retryable on my getOrCreateEntity method because it seems to be the simplest solution (at least, I think so). This method is called from another method annotated with @Transactional.

So, I have two questions:

  1. Do I need to add @Transactional(propagation = Propagation.REQUIRES_NEW) to my method with @Retryable?
  2. Do I need to catch the potential exception (DataIntegrityViolationException) and, in the catch block, retrieve the entity that has already been created?

Here is the code :

@Retryable(
        retryFor = {DataIntegrityViolationException.class},
        maxAttempts = 2,
        backoff = @Backoff(delay = 100)
)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public T getOrCreateEntity(UUID entityUuid) {
    T entity = findEntityByUuid(entityUuid);
    if (entity != null) {
        return entity;
    }

    try {
        log.info("Creating entity with UUID {}", entityUuid);
        T newEntity = createNewEntity(entityUuid);
        return repository.save(newEntity);
    } catch (DataIntegrityViolationException e) {
        log.warn("Concurrent insert detected, returning existing entity");
        return findEntityByUuid(entityUuid);
    }
}

So, as I mentioned, getOrCreateEntity is called by a method that already holds a transactional context.

Thanks in advance,

I have an issue when two threads try to create an entity in my database. The first thread checks if the object exists, sees that it is not there, and then creates it. However, at the same time, the second thread also checks if the object exists and, not finding it, tries to create it as well.

I want to solve this issue using @Retryable on my getOrCreateEntity method because it seems to be the simplest solution (at least, I think so). This method is called from another method annotated with @Transactional.

So, I have two questions:

  1. Do I need to add @Transactional(propagation = Propagation.REQUIRES_NEW) to my method with @Retryable?
  2. Do I need to catch the potential exception (DataIntegrityViolationException) and, in the catch block, retrieve the entity that has already been created?

Here is the code :

@Retryable(
        retryFor = {DataIntegrityViolationException.class},
        maxAttempts = 2,
        backoff = @Backoff(delay = 100)
)
@Transactional(propagation = Propagation.REQUIRES_NEW)
public T getOrCreateEntity(UUID entityUuid) {
    T entity = findEntityByUuid(entityUuid);
    if (entity != null) {
        return entity;
    }

    try {
        log.info("Creating entity with UUID {}", entityUuid);
        T newEntity = createNewEntity(entityUuid);
        return repository.save(newEntity);
    } catch (DataIntegrityViolationException e) {
        log.warn("Concurrent insert detected, returning existing entity");
        return findEntityByUuid(entityUuid);
    }
}

So, as I mentioned, getOrCreateEntity is called by a method that already holds a transactional context.

Thanks in advance,

Share Improve this question edited Feb 6 at 6:23 M. Deinum 125k22 gold badges230 silver badges246 bronze badges asked Feb 5 at 21:25 magnetiktankmagnetiktank 1252 silver badges10 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 0

If you do } catch (DataIntegrityViolationException e) {, then you don't need that @Retryable, since in the catch block you do that really manually.

The Propagation.REQUIRES_NEW depends on your business logic. If it really requires that entity has to be there independently of the current transaction, then yes, you would need a new one just for this operation. Otherwise it might be OK to have such a retrieval as part of existing transaction. Yes, it might fail in the end because entity is already there by another transaction, but that might be OK as well according to the whole business logic of this call chain.

发布评论

评论列表(0)

  1. 暂无评论