본문 바로가기
실험실

DB 통신 중 연결이 끊긴다면 어떻게 될까? (feat. JPA)

by CodingMasterLSW 2025. 6. 14.

Service는 트랜젝션 단위로 이루어져 있다.  만약 save 이후에 DB 네트워크가 끊긴다면 어떻게 될까? 

 

@Entity
public class Member {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    protected Member() {
    }

    public Member(String name) {
        this.name = name;
    }
}
@Service
public class MemberService {
    
    private final MemberRepository memberRepository;

    public MemberService(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }
    
    @Transactional
    public Member save(String name) {
        Member savedMember = memberRepository.save(new Member(name));
        // 이 지점에서 네트워크가 끊긴다면?
        return savedMember;
    }
}

 

 

필자가 해당 실험을 하게 된 계기는 다음과 같다.

 

1) save() 시점에서 Member가 저장이 된다. 

2) 네트워크가 끊긴다.

3) 에러가 발생했기에 트랜젝션 시작 지점으로 rollback을 해야 하는데 DB와 연결이 끊겨버렸음... 롤백을 정상적으로 할 수 있을까? 네트워크가 끊겼는데 DB에 어떻게 접근을 할 수 있는 거지? 와 같은 의문점을 가졌고, 실험을 하게 되었다.

 

첫 번째 예상

1) save 시점에 DB에 Member가 저장이 된다.

2) 에러가 났기 때문에 DB에 저장된 Member를 rollback 시도한다.

3) 연결이 끊겼기에 rollback이 불가하고, Member가 그대로 남아있는 문제가 발생한다...!

 

두 번째 예상

1) save 시점에 DB에 Member가 저장이 된다.

2) 에러가 났기 때문에 DB에 저장된 Member를 rollback 시도한다.

3) 내부적으로 어찌저찌 rollback을 해준다.

 

이제 실험을 해보자!


@Transactional
public Member save(String name) throws InterruptedException {
    Member savedMember = memberRepository.save(new Member(name));
    Thread.sleep(60000);
    return savedMember;
}

 

save 이후에 스레드를 1분간 대기시켜 놓고, 그 사이에 DB를 종료시킬 계획이다.

 

@RestController
public class MemberController {

    private final MemberService memberService;

    public MemberController(MemberService memberService) {
        this.memberService = memberService;
    }

    @PostMapping("/member")
    public void create() throws InterruptedException {
        memberService.save("jenson");
        System.out.println("작업 종료");
    }

 

간단한 컨트롤러를 하나 생성했다.

 

이후에 해당 uri로 http 요청을 보내고, 60초 안에 db를 종료시켜 봤다. 

두근두근... 어떻게 될까?

 

 

우선 EOFException이라는 오류가 발생한다...! 오류 내용을 대충 읽어보니, 요청은 성공적으로 도착했지만 응답이 오지 않아 에러가 발생한 것 같다.

 

그렇다면 저장한 Member는 어떻게 되었을까?? 남아있을까?

 

오... 연결이 끊겼는데 롤백을 어떻게 한 걸까... 신기하다

 

그런데 과연 롤백을 한 걸까? 혹시 flush 시점이 아니라, 트랜젝션이 끝난 이후 commit 시점에 데이터가 들어오는 걸 수도 있지 않을까?

 

이번에는 save() 이후 스레드가 쉬고 있을 때, Member가 정말로 DB에 저장되었을지 검증을 해보자.

 

오... 쿼리문은 날라갔는데 저장된 데이터가 아무것도 없다.

 

 

작업 종료 메세지가 찍힌 이후에 데이터가 들어오는 걸 확인할 수 있었다. 아주 흥미로운 결과다!


실험 결과를 정리해보자.

1) save() 시점(flush 시점)에 쿼리문은 날아가지만, 실제 DB에 값이 저장되지는 않음.

2) 트랜젝션이 끝나는 시점(commit 시점)에 실제 DB에 값이 반영이 됨.

 

위와 같은 시점에 데이터가 반영이 된다. 예상 1, 2가 전부 틀렸다ㅋㅋ...

 

조금 더 관련 정보를 찾아봤는데 예외가 발생하면 commit()을 날리는 게 아니라 rollback()을 수행한다고 한다. 커넥션이 끊어졌는데 어떻게 롤백을 하는지 궁금했는데, 내부적으로 모니터링을 하고 끊기면 알아서 롤백처리를 해주는 것 같다.

 

 

  • 데이터베이스 서버는 클라이언트(애플리케이션)와의 연결 상태를 주기적으로 모니터링합니다.
  • 일정 시간 동안 클라이언트로부터 아무런 활동이 없거나(timeout), 네트워크 패킷 교환이 불가능하다고 판단되면, DB 서버는 해당 클라이언트의 커넥션이 비정상적으로 종료(abnormal termination)되었다고 감지합니다.
  • DB 서버는 비정상적으로 종료된 커넥션에 할당되어 있던 모든 진행 중인 트랜잭션을 자동으로 롤백 처리합니다.
  • 이 롤백 과정은 앞서 트랜잭션 로그에 기록되었던 변경 사항들을 취소하는 방식으로 이루어집니다. 즉, 트랜잭션 시작 이전의 상태로 되돌립니다.

(Gemini의 답변)

 

쨋든 네트워크가 끊겨도 DB가 알아서 잘 처리해 준다. 신기하다!

 

 

잘못된 정보 지적은 언제나 감사합니다.