[stock101] LOCK을 누가 계속 잡는 문제.

2026. 1. 21. 14:17·Archive(완료된 내용)/포트폴리오 강화

문제점 코드 (Before)

@Transactional  // ← 트랜잭션 시작
public int updateStocksFromMst(MultipartFile file) {
    List<StockMstDto> mstList = parseMstFile(file);
    
    int updatedCount = 0;
    for (StockMstDto mst : mstList) {
        try {
            // ... DB 작업 (INSERT/UPDATE)
            stockMapper.insertStock(newStock);  // ← 여기서 SQL 에러!
            updatedCount++;
        } catch (Exception e) {
            log.error("Failed...", e);  // ← 예외를 잡아서 삼킴
        }
    }
    
    return updatedCount;  // ← 메서드는 정상 종료처럼 보임
}

핵심 문제:

1. 예외를 catch해서 삼켜버림

catch (Exception e) {
    log.error(...);  // 로그만 찍고 끝
}
// 예외가 메서드 밖으로 나가지 않음!

2. Spring @Transactional의 롤백 조건

  • Spring은 unchecked exception(RuntimeException)이 메서드 밖으로 throw되어야 롤백합니다
  • 예외를 catch하면 Spring은 "정상 종료"로 판단합니다
  • 하지만 커밋하지도 않고 트랜잭션이 hanging 상태로 남습니다

3. 좀비 트랜잭션 생성

시작: @Transactional 메서드 진입 → DB 커넥션 획득, 트랜잭션 시작 중간: INSERT 실패 → Exception 발생 → catch로 잡힘 → Spring은 예외를 못 봄 끝: return updatedCount → 메서드는 "정상 종료" 결과: 커밋도 롤백도 안됨 → 트랜잭션 hanging → DB 락 유지 → HikariCP 커넥션 반환 안됨

 

4. 실제 발생한 상황

13:48:38 - MST 업로드 시도 → stock_id AUTO_INCREMENT 누락으로 INSERT 실패 → 예외를 catch로 삼킴 → 트랜잭션이 10분 이상 RUNNING 상태로 남음 → users 테이블 락 유지 (왜? 같은 커넥션 세션 내에서 여러 테이블 접근) 14:03:14 - 로그인 시도 → UPDATE users SET last_login_at... 실행 → 기존 트랜잭션(ID 1051)이 락을 잡고 있어서 블로킹 → 30초 타임아웃 발생


수정된 코드 (After)

@Transactional  // ← 트랜잭션 시작
public int updateStocksFromMst(MultipartFile file) {
    List<StockMstDto> mstList = parseMstFile(file);
    
    int updatedCount = 0;
    
    // try-catch 제거! ← 핵심 변경
    for (StockMstDto mst : mstList) {
        Stock existingStock = stockMapper.selectStockByCode(mst.getStockCode());
        
        if (existingStock != null) {
            stockMapper.updateStockBasicInfo(updateStock);
        } else {
            stockMapper.insertStock(newStock);  // ← 에러 발생 시 즉시 throw
        }
        updatedCount++;
    }
    
    return updatedCount;  // ← 정상 종료 시에만 도달
}

수정 핵심:

1. try-catch 완전 제거

// Before: catch로 예외 삼킴
try {
    stockMapper.insertStock(newStock);
} catch (Exception e) {
    log.error(...);  // ← 예외 소멸
}

// After: 예외를 자연스럽게 propagate
stockMapper.insertStock(newStock);  // ← 에러 시 즉시 throw

2. Spring의 자동 롤백 활성화

시나리오 1 (성공): → 모든 INSERT/UPDATE 성공 → 메서드 정상 종료 → Spring이 COMMIT 실행 → 커넥션 반환

시나리오 2 (실패): → INSERT에서 SQLException 발생 → unchecked exception이 메서드 밖으로 throw → Spring이 예외 감지 → 자동으로 ROLLBACK 실행 ← 핵심! → 커넥션 반환 → 트랜잭션 정상 종료

3. All-or-Nothing 보장

  • 100개 종목 중 99번째에서 에러 → 전체 롤백
  • 데이터 일관성 보장
  • 부분 성공으로 인한 데이터 불일치 방지

4. 추가 개선사항

  • 수천 개 종목 업로드 시 로그 과다 방지
  • 디버그 시에만 상세 로그 활성화

동작 비교

Before (문제 코드)

  1. 트랜잭션 시작
  2. INSERT 실패 → Exception
  3. catch로 잡음 → 예외 삼킴
  4. 계속 진행 (다음 종목)
  5. return updatedCount
  6. Spring: "정상 종료네? 근데 커밋할 게 없네?"
  7. 트랜잭션 hanging → 락 유지 → 타임아웃 유발

After (수정 코드)

  1. 트랜잭션 시작
  2. INSERT 실패 → Exception
  3. 예외가 메서드 밖으로 throw
  4. Spring: "예외 감지! ROLLBACK!"
  5. 트랜잭션 즉시 종료 → 락 해제 → 커넥션 반환
  6. 컨트롤러로 예외 전파 → 500 에러 응답

Spring @Transactional의 롤백 규칙

@Transactional
public void method() {
    // Case 1: RuntimeException → 자동 롤백 ✅
    throw new RuntimeException();
    
    // Case 2: Checked Exception → 커밋됨 ⚠️
    throw new IOException();  // 롤백 안됨!
    
    // Case 3: 예외 catch → 커밋됨 ⚠️
    try {
        throw new RuntimeException();
    } catch (Exception e) {
        // 삼켜버림 → Spring은 정상 종료로 판단
    }
}

우리 코드는 Case 3에 해당했고, 이를 Case 1로 변경했습니다.

저작자표시 비영리 변경금지 (새창열림)

'Archive(완료된 내용) > 포트폴리오 강화' 카테고리의 다른 글

[stock101] dart연동 및 ksi 연동 그리고 리팩토링 -4일차  (1) 2026.01.22
[stock101] KIS 코스피 코스닥 종목 정보 매일 최신화하기 - 3일차  (1) 2026.01.21
[stock101] KIS API연동 웹소켓 - 2일차  (1) 2026.01.20
[stock101] pdf파일 업로드 및 AI 셋팅 - 1일차  (0) 2026.01.19
[임베딩]  (0) 2026.01.17
'Archive(완료된 내용)/포트폴리오 강화' 카테고리의 다른 글
  • [stock101] dart연동 및 ksi 연동 그리고 리팩토링 -4일차
  • [stock101] KIS 코스피 코스닥 종목 정보 매일 최신화하기 - 3일차
  • [stock101] KIS API연동 웹소켓 - 2일차
  • [stock101] pdf파일 업로드 및 AI 셋팅 - 1일차
오늘은치킨이닭
오늘은치킨이닭
개발로 세상을 밝히자.(억지 맞음)
  • 오늘은치킨이닭
    개발세밝
    오늘은치킨이닭
  • 전체
    오늘
    어제
    • 분류 전체보기 (80)
      • Project(마감 기한이 정해진 목표) (2)
        • Docker(도커) (1)
        • Django(장고) (0)
        • 부트캠프 (1)
      • Archive(완료된 내용) (59)
        • 재취업준비 (8)
        • 포트폴리오 강화 (24)
        • 부트캠프 (3)
        • 팁 (2)
        • 데이터베이스 (2)
        • SQL (12)
        • 백엔드 (5)
        • 프론트엔드 (1)
        • 유니티(Unity) (2)
      • Area(일생동안 지속 유지하는 활동,마감X) (16)
        • 게임 (2)
        • 코딩테스트 (12)
        • 운영체제 (0)
        • DB (2)
      • Resource(지속적 관심을 갖는 주제분야) (1)
        • 애니메이션 (0)
        • 내가 선정한 맛집 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    칼국수맛집
    명동맛집
    유니티 #설치 #방법 #다운
    고클린 #cpu온도보는법 #cpu온도
    롤 #룬 #자동적용 #블리츠 #다운로드 #도움 #TIP #브론즈 #아이언 #브실골 #아브실
    DB #데이터베이스
    인포그래픽 #자기소개서 #자기소개 #명함삭제
    맛집
    명동교자
    명동
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
오늘은치킨이닭
[stock101] LOCK을 누가 계속 잡는 문제.
상단으로

티스토리툴바