개요
안녕하세요 빈코입니다. 오늘은 제가 실무에서 작업을 하면서 겪었던 오류와 해결과정을 포스팅하려고 합니다. 특정 조건들을 통해 데이터의 개수를 구할 때, Integer 혹은 int로 정의를 하게 되는데 해당 과정에서 잘못 된 선언으로 인해 결함이 나오게 되었습니다. 하단에서 좀 더 자세히 살펴볼게요😄
겪은 오류📙
제가 겪은 오류는 특정 조건으로 DB의 데이터 개수를 구할 때 int 형으로 선언하고 진행했었는데, 해당 조건의 데이터가 아예 없어서 NULL 오류를 겪게 되었습니다.
CommonMapper.getLogCount attempted to return null from a method with a primitive return type(int) // 오류 내용
Mybatis와 같은 Mapper를 사용할 때, SQL의 결과 값은 데이터베이스의 데이터 타입을 Java 객체로 변환하는 과정이 필요한데, 조건에 맞는 데이터가 없어서 Null을 반환하였고, Null을 int로 변환하는 과정에서 해당 오류가 발생하여 이후의 모든 로그를 쌓지 못하는 결함이 발생했습니다.
로그 자체는 실무에서는 상당히 중요한 자료이기 때문에, 상당히 크리티컬 한 이슈였습니다. 해결과정은 생각보다 간단한데 하단에서 이어 나가볼게요😁
Integer VS int📘
Java의 원시 데이터 타입 중 하나로, 값을 저장하는 스택 메모리에 직접 저장되는 int는 Null 값을 가질 수 없습니다. 반드시 초기화가 필요하며 Default 값은 0입니다. 또 다른 특징으로는 기본적인 산술 연산이 빠르고 메모리 사용량이 적은 장점을 가지고 있습니다. 또한, 값만 저장하는 역할을 하고 추가적인 메서드는 제공하지 않습니다.
반면에, Integer는 java.lang.Integer 클래스의 인스턴스로, 기본 타입인 int를 감싸는 Wrapper Class입니다. Integer는 Null 값을 허용하며 다양한 유틸리티 메서드(ex: Integer.paresInt(), Integer.compare() 등)를 제공합니다. 값은 힙 메모리에 저장되며, 객체이기 때문에 추가적인 메모리 및 성능 비용이 드는 단점이 있습니다.
상위에서 설명한 바와 같이 Mapper는 SQL의 결과 값을 Java 객체로 변환하는 과정이 필요한데, 이때 Null 값을 허용하는 Integer로 선언하는 것이 제가 겪은 오류의 해결 과정이었습니다.
💡 Mapper 정의 시에는 데이터가 없을 경우를 고려하여 Null 값을 고려하는 Integer로 선언하는 것이 일반적으로 좋습니다
예제📗
한 가지 다른 예제로 회원가입을 진행할 때 중복 아이디를 검사하는 로직이 있을 텐데, 해당 로직은 아래 예시와 같이 쿼리를 작성하는 경우가 많습니다.
// 동일 아이디 갯수 구하는 로직
SELECT count(*)
FROM table_name
WHERE user_id = #{user_id} // 조건
이런 식으로 쿼리를 작성하면 사실 Mapper를 선언할 때 Integer이든 int든 상관없이 작동을 하게 됩니다. count() 메서드는 결괏값이 없더라도 0을 반환하기 때문이죠?
하지만 위처럼 쿼리를 작성하면 해당 테이블의 데이터가 많을 때 서버에 과부하가 발생하게 됩니다. SELECT count(*)는 조건에 맞는 전체 레코드 수를 반환합니다. 중복 여부를 확인할 때 반환되는 숫자는 중요하지 않고, 존재 여부만 확인하려는 경우에도 실행되는 문제가 있으며, 전체 매칭된 결과를 계산하기 때문에 불필요한 작업이 추가로 포함될 수 있습니다. 즉, 동일 아이디를 찾더라도 모든 테이블 데이터를 비교한다는 불필요한 작업을 수행한다는 뜻입니다.
반면에, 해당 테이블의 PK값이 있을 때 해당 PK 값을 조회하는 식으로 변경하면 어떻게 될까요?
SELECT unum // unum은 회원 테이블의 PK(int) 값이라고 가정
FROM table_name
WHERE user_id = #{user_id};
위처럼 쿼리를 작성하면 조건에 맞는 첫 번째 레코드의 PK 값인 unum을 반환하게 됩니다, 즉 데이터가 많아도 첫 번째 매칭되는 레코드가 발견되면 즉시 반환이 가능하므로 존재 여부를 확인하는 데는 훨씬 빠른 속도를 자랑합니다.
💡 물론 해당 쿼리에 대한 Mapper는 Integer로 선언하고, 서비스단에서 try~catch 문 사용 및 Null 처리도 진행해야겠죠?
마치며
지금까지 Integer와 int의 차이점과 간단한 예제를 살펴보았습니다. 사실 개발에 입문했을 당시에 공부하던 내용이라서 오류가 발생했을 때 많이 반성하게 되었네요😅
다음 포스팅에서 뵐게요 :)
'TIL' 카테고리의 다른 글
Java 이미지 파일 다운로드 기능 구현하기(예제 포함) (1) | 2024.12.27 |
---|---|
js 드래그 앤 드롭(drag&drop) 사용하기 (0) | 2024.12.18 |
PostgerSQL Upsert 쿼리 개념 및 대용량 속도 차이 예제 (0) | 2024.11.23 |
Java 파일 업로드 구현하기 및 Progress Bar 설정 (3) | 2024.11.16 |
Java 회원가입 및 로그인 비밀번호 Hash 비교 방법 (0) | 2024.11.12 |