Develop/Trouble Shooting
DB 커넥션 관련 에러 - 트랜잭션
jaeyoungb
2025. 3. 29. 15:43
# 에러 메시지
### 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);
# 회고 및 추가 해결책
- 트랜잭션이 필요 없는 검증 로직은 트랜잭션 외부에서 처리.
- Spring의
@Transactional
어노테이션 사용.
(@Transactional은 프록시 기반이라 내부 메서드 호출 시 트랜잭션이 적용되지 않음) - 트랜잭션이 열린 상태에서 return할 경우, rollback 또는 commit을 명시적으로 처리.
- 트랜잭션 propagation 설정에 따라 동작이 달라질 수 있음.