Oracle 기반 프로젝트를 PostgreSQL로 마이그레이션하거나, 다중 DB를 지원할 때 흔히 겪는 문자열 ↔ 숫자 암묵적 형변환(Implicit Casting) 오류 정리글입니다.

 

💡 한 줄 요약

Java에서 숫자형 파라미터를 String("2")으로 넘어온 상태로 MyBatis에 바인딩했습니다. Oracle은 '2' → NUMBER 암묵적 형변환을 허용하지만, PostgreSQL은 엄격하게 거부하여 에러가 발생했습니다.

 

1. 증상 및 에러 로그

🚨 PostgreSQL Error Log

SQL
 
ERROR: column "insert_no" is of type bigint but expression is of type character varying
Hint: You will need to rewrite or cast the expression.

📝 실제 실행된 SQL 로그

SQL
 
INSERT INTO TB_IAM_TEMP_SAVE_MASTER ( ..., INSERT_NO, ... )
VALUES ( 16::bigint, ..., '2', CURRENT_TIMESTAMP, ... )
--                        ^^^ 문자열('varchar')로 바인딩됨!
  • PostgreSQL 컬럼 타입: bigint (또는 integer)
  • 넘어온 데이터: '2' (varchar)
  • 특이사항: 동일한 Java 로직과 SQL 흐름인데 Oracle에서는 정상 실행됨.

 

2. 원인 분석: Oracle vs PostgreSQL

구분Oracle / PostgreSQL

 

컬럼 타입 NUMBER(38,0) BIGINT / INT
'2' (문자열) → 숫자 처리 암묵적 변환 허용 (OK) 암묵적 변환 거부 (Error)
결과 정상 Insert varchar → bigint 형변환 에러 발생
특징 비교적 타입 검사에 관대함 Prepared Statement 및 타입 검사가 엄격함
 

3. 자주 헷갈리는 Q&A

Q1. jdbcType=BIGINT를 붙였는데 왜 변환이 안 되나요?

A. MyBatis의 jdbcType 설정은 Java의 String을 Long으로 자동 변환해 주지 않습니다.

jdbcType은 주로 값이 null일 때 DB에 어떤 SQL Type으로 넣어줄지 알려주는 힌트 역할을 합니다. MyBatis는 기본적으로 Java 변수의 실제 데이터 타입을 보고 setXxx()를 결정합니다.

XML
 
<!-- Java 필드가 String이면 jdbcType을 BIGINT로 적어도 setString()이 호출되어 '2'로 찍힙니다. -->
#{insertNo, jdbcType=BIGINT} 

Q4. 그럼 jdbcType=BIGINT는 지워도 되나요?

A. 상황에 따라 다릅니다.

  1. SQL에서 ::bigint 명시적 캐스트를 수행하는 경우 ➔ 없어도 됨
  2. Java에서 이미 Long 타입으로 넘겨주는 경우 ➔ 없어도 됨
  3. 해당 파라미터에 null이 들어갈 가능성이 있는 경우 ➔ jdbcType을 명시해 주는 것이 안전함

4. 해결 방법 : SQL에서 명시적 형변환

MyBatis 쿼리문에서 PostgreSQL 전용 캐스트(::bigint)를 붙여줍니다.

 
INSERT INTO TB_IAM_TEMP_SAVE_MASTER (
    INSERT_NO
) VALUES (
    #{insertNo}::bigint
)

 

 

📌 최종 요약

  1. Oracle과 PostgreSQL의 차이: Oracle은 '2' → NUMBER 자동 변환을 해주지만, PostgreSQL은 strict하여 거부함.
  2. jdbcType=BIGINT의 오해: Java의 String을 자동으로 숫자로 변환해 주는 옵션이 아니며, 단순 NULL 처리 힌트에 가까움.
  3. 실무 해결 방안:
    • SQL 매핑 파일에서 #{insertNo}::bigint 처리
    • 또는 Java 레이어에서 Long 타입으로 캐스팅 후 바인딩

+ Recent posts