본문 바로가기
Develop/Trouble Shooting

DB 커넥션 관련 에러 - 트랜잭션

by jaeyoungb 2025. 3. 29.

# 에러 메시지

### Caused by: co[http://m.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException:](http://m.mysql.cj.jdbc.exceptions.MySQLTransactionRollbackException:) Lock wait timeout exceeded; try restarting transaction\
### Error querying database.  Cause: org.springframework.jdbc.CannotGetJdbcConnectionException: Failed to obtain JDBC Connection; nested exception is java.sql.SQLException: Cannot get a connection, general err
### Error querying database.  Cause: java.sql.SQLNonTransientConnectionException: No operations allowed after connection closed.

 


# 원인

비즈니스 로직 초반부 특정 조건을 검증하고, 검증 실패 시 return으로 api 실행을 중단하는 로직 존재.
트랜잭션이 시작된 후 검증을 수행했기에, 트랜잭션이 정상 종료되지 않은 상태에서 api가 종료됨.

 

[ 문제 java 코드 ]

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus txStatus = txManager.getTransaction(def);

...

// ex) 검증 후 return → 트랜잭션이 종료되지 않고 api 중단
if (!isValid()) {
    return;
}

...

txManager.commit(txStatus);

 

 


# 해결

해당 검증 로직은 DB 접근이 필요 없으므로, 트래잭션을 시작하기 전에 수행하도록 변경. (단순 검증문 위치 변경)

 

[ 수정된 java 코드 ]

// 트랜잭션 시작 전 검증 수행
if (!isValid()) {
    return;
}

DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus txStatus = txManager.getTransaction(def);

...

txManager.commit(txStatus);

 


# 회고 및 추가 해결책

  1. 트랜잭션이 필요 없는 검증 로직은 트랜잭션 외부에서 처리.
  2. Spring의 @Transactional 어노테이션 사용.
    (@Transactional은 프록시 기반이라 내부 메서드 호출 시 트랜잭션이 적용되지 않음)
  3. 트랜잭션이 열린 상태에서 return할 경우, rollback 또는 commit을 명시적으로 처리.
  4. 트랜잭션 propagation 설정에 따라 동작이 달라질 수 있음.