-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[fix] 좋아요 수 동시성 이슈 처리 #249
base: develop
Are you sure you want to change the base?
Conversation
따봉드려요 👍 고생하셧슴둥 |
Thread.sleep(retry.backoff()); | ||
} | ||
} | ||
throw new BadRequestException(HeartErrorCode.HEART_COUNT_CONCURRENCY_ERROR); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
conflict exception 아닌가요?
글구 이거 좋아요 중복 눌렀을 때도 409 나가는데 둘이 클라에서 구분 안되지 않나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이부분 클라와 상의한번 해보고 다시 말씀드릴게요
for (int attempt = 0; attempt < retry.maxAttempts(); attempt++) { | ||
try { | ||
return joinPoint.proceed(); | ||
} catch (OptimisticLockException | ObjectOptimisticLockingFailureException | StaleObjectStateException e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
objectOptimisticLockingFailureException만 잡으면 되지 않나요??
해당 예외는 jpatransactionmanager의 doCommit method 실행시 발생할 것인데,
protected void doCommit(DefaultTransactionStatus status) {
JpaTransactionObject txObject = (JpaTransactionObject)status.getTransaction();
if (status.isDebug()) {
this.logger.debug("Committing JPA transaction on EntityManager [" + txObject.getEntityManagerHolder().getEntityManager() + "]");
}
try {
EntityTransaction tx = txObject.getEntityManagerHolder().getEntityManager().getTransaction();
tx.commit();
} catch (RollbackException var6) {
Throwable var5 = var6.getCause();
if (var5 instanceof RuntimeException runtimeException) {
DataAccessException dae = this.getJpaDialect().translateExceptionIfPossible(runtimeException);
if (dae != null) {
throw dae;
}
}
throw new TransactionSystemException("Could not commit JPA transaction", var6);
} catch (RuntimeException var7) {
throw DataAccessUtils.translateIfNecessary(var7, this.getJpaDialect());
}
}
translateExceptionIfPossible의 구현은 아래와 같습니다
@Nullable
public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
if (ex instanceof HibernateException hibernateEx) {
return this.convertHibernateAccessException(hibernateEx);
} else {
if (ex instanceof PersistenceException) {
Throwable var3 = ex.getCause();
if (var3 instanceof HibernateException) {
hibernateEx = (HibernateException)var3;
return this.convertHibernateAccessException(hibernateEx);
}
}
return EntityManagerFactoryUtils.convertJpaAccessExceptionIfPossible(ex);
}
}
@Nullable
public static DataAccessException convertJpaAccessExceptionIfPossible(RuntimeException ex) {
if (ex instanceof IllegalStateException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
} else if (ex instanceof IllegalArgumentException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
} else if (ex instanceof EntityNotFoundException) {
EntityNotFoundException entityNotFoundException = (EntityNotFoundException)ex;
return new JpaObjectRetrievalFailureException(entityNotFoundException);
} else if (ex instanceof NoResultException) {
return new EmptyResultDataAccessException(ex.getMessage(), 1, ex);
} else if (ex instanceof NonUniqueResultException) {
return new IncorrectResultSizeDataAccessException(ex.getMessage(), 1, ex);
} else if (ex instanceof QueryTimeoutException) {
return new org.springframework.dao.QueryTimeoutException(ex.getMessage(), ex);
} else if (ex instanceof LockTimeoutException) {
return new CannotAcquireLockException(ex.getMessage(), ex);
} else if (ex instanceof PessimisticLockException) {
return new PessimisticLockingFailureException(ex.getMessage(), ex);
} else if (ex instanceof OptimisticLockException) {
OptimisticLockException optimisticLockException = (OptimisticLockException)ex;
return new JpaOptimisticLockingFailureException(optimisticLockException);
} else if (ex instanceof EntityExistsException) {
return new DataIntegrityViolationException(ex.getMessage(), ex);
} else if (ex instanceof TransactionRequiredException) {
return new InvalidDataAccessApiUsageException(ex.getMessage(), ex);
} else {
return ex instanceof PersistenceException ? new JpaSystemException(ex) : null;
}
}
실행되어 결국
ObjectOptimisticLockingFailureException 상속한 JpaOptimisticLockingFailureException이 던져지는 것으로 보입니다.
protected DataAccessException convertHibernateAccessException(HibernateException ex) {
DataAccessException dae;
if (this.jdbcExceptionTranslator != null && ex instanceof JDBCException jdbcEx) {
dae = this.jdbcExceptionTranslator.translate("Hibernate operation: " + jdbcEx.getMessage(), jdbcEx.getSQL(), jdbcEx.getSQLException());
if (dae != null) {
return dae;
}
}
if (this.transactionExceptionTranslator != null && ex instanceof org.hibernate.TransactionException) {
Throwable var7 = ex.getCause();
if (var7 instanceof SQLException) {
SQLException sqlEx = (SQLException)var7;
dae = this.transactionExceptionTranslator.translate("Hibernate transaction: " + ex.getMessage(), (String)null, sqlEx);
if (dae != null) {
return dae;
}
}
}
if (ex instanceof JDBCConnectionException) {
return new DataAccessResourceFailureException(ex.getMessage(), ex);
} //생략
else if (ex instanceof StaleStateException) {
return new ObjectOptimisticLockingFailureException(ex.getMessage(), ex);
}
요기서는 staleobjectstateexception -> ObjectOptimisticLockingFailureException으로 변환해서 던지는 것으로 보입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그래도 혹시 모르니 테스트 해보시길
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
aop로 하셨다는 것은.. 다른곳에서도 공통적으로 쓰일 로직을 만드셨다는 것이니 common이 맞을 것 같습니다 |
Related Issue 📌
close #248
Description ✔️
To Reviewers
테스트 완료
RetryAspect 클래스 위치를 api.common으로 옮길지 지금처럼 store 패키지 하위에 위치시킬지 고민입니다