error

[error] ORA-06502: PL/SQL: 수치 또는 값 오류: 원시 변수 길이가 너무 깁니다 (For Select & Insert)

dddzr 2025. 8. 9. 16:36

[error] ORA-06502: PL/SQL: 수치 또는 값 오류: 원시 변수 길이가 너무 깁니다  (For Select & Insert)

 

📌에러 환경

공지사항에 길이가 긴 글 등록 시 오류.

오라클 DB 사용.

게시글 데이터 타입은 BLOB.

 

🚨에러1

### Error updating database.  Cause: java.sql.SQLException: ORA-06502: PL/SQL: 수치 또는 값 오류: 원시 변수 길이가 너무 깁니다

ORA-06512: "SYS.UTL_RAW"

 

📖 기존 sql

- Insert

<!-- 공지 사항 저장 -->
<update id="insertNotice" parameterType="NoticeVO">
        MERGE INTO TB_NOTI_MGMT target
        USING (
    SELECT
        #{sno} AS sno,
        #{title} AS title,
        UTL_RAW.CAST_TO_RAW(#{content}) AS cont
    FROM DUAL
) source   
        ON  target.SNO = #{sno}
        WHEN MATCHED THEN
            UPDATE SET
                TITLE = source.title,
                CONTENT = source.content
        WHEN NOT MATCHED THEN
            INSERT ( SNO, TITLE, CONTENT)
            VALUES (source.sno, source. title, source.content)
</update>

 

- Select

<!-- 공지 수정화면 조회 -->
<select id="selectNotice" resultType="NoticeVO"  parameterType="NoticeVO">
SELECT
A.SNO     AS sno,
A. TITLE  AS title,
UTL_RAW.CAST_TO_VARCHAR2(A.CONTENT)      AS content,
A.VIEW_CNT AS viewCnt
FROM TB_NOTI_MGMT A
WHERE 1=1
AND A.SNO = #{sno}
</select>

 

🔥원인

  • CAST_TO_RAW()는 문자열을 RAW로 변환하는데,
    VARCHAR2 → RAW 변환 시 길이 제한은 32,767바이트(PL/SQL), 4000바이트(SQL)

 

🛠 해결방법

  1. UTL_RAW 함수를 쿼리에서 모두 제거
  2. 애플리케이션에서 String byte변환을 해주면 된다.

 

나는 관리자 시스템에서 공지사항 등록 및 수정, 일반 사용자 시스템에서 공지사항 조회로 나누어져 있어서 사용자 시스템은 vo방식만 이용하고, 관리자 시스템에서 등록할 때에는 서비스단에 적용했다.

 

2가지 방법 중 하나를 적용하면 된다.

 

✅1. JAVA(spring service)에서 String <-> byte 변환

📖 Insert

try {
    String strContent  = abstractVo.getInfo("content");
    byte[] blobContent = strContent.getBytes("UTF-8");
    abstractVo.add("content", blobContent);
} catch(Exception e) {
	logger.error( e.getMessage() );
}

 

📖 Select

if(abstractVo == null) {
	abstractVo.put("contentStr", "");
}else {
    Byte[] ByteCont = (Byte[])abstractVo.get("content");
    byte[] byteCont =  ArrayUtils.toPrimitive(ByteCont);
    String strContent = null;
    try {
        strContent = new String(byteCont, "UTF-8" );
    }catch(Exception e) {
        logger.error(e.getMessage());
    }
	abstractVo.put("contentStr", strContent);
}



✅2. Vo에서 변환

아래 vo가 이미 적용되어 있었기 때문에 sql만 지웠다.

  • getCont()
  • setCont(String cont)
  • setCont(byte[] cont)
import java.nio.charset.StandardCharsets;
import java.util.List;

public class NoticeVO {
    private String sno = "";
    private String title = "";
    private byte[] content;

    private List<FileVO> delFiles;
    private List<FileVO> uploadedFiles;

    // 일반 필드 getter, setter 생략
    @Override
    public String toString() {
        return "NoticeVO [sno=" + sno + ", title=" + title + ", content="+ content + "]";
    }

    public String getContent() { // BLOB 데이터를 문자열로 변환 (UTF-8 인코딩 사용)
        if (content != null) {
            return new String(content, StandardCharsets.UTF_8);
        }
        return null;
    }

    public void setContent(String content) { // 문자열을 BLOB(byte[])로 변환 (UTF-8 인코딩 사용)
        if (cont != null) {
            this.content = content.getBytes(StandardCharsets.UTF_8);
        } else {
            this.content = null;
        }
    }

    public void setContent(byte[] content) { this.content = content; }
    public List<FileVO> getUploadedFiles() { return uploadedFiles; }
    public void setUploadedFiles(List<FileVO> uploadedFiles) { this.uploadedFiles = uploadedFiles; }
    public List<FileVO> getDelFiles() { return delFiles; }
    public void setDelFiles(List<FileVO> delFiles) { this.delFiles = delFiles; }

}



📌에러2

근데 위처럼 수정 후에도 에러가 발생했다.

Request processing failed; nested exception is org.springframework.jdbc.UncategorizedSQLException: Error attempting to get column 'CONT' from result set. Cause: java.sql.SQLException: 부적합한 열 유형: getString not implemented for class oracle.jdbc.driver.T4CBlobAccessor

 

🔥원인

  • Oracle BLOB 타입 컬럼을 MyBatis가 getString() 으로 읽으려고 해서 발생
  • BLOB은 getString()으로 직접 조회 불가

🛠 해결법

  • resultMap 추가, jdbcType="BLOB" 과 javaType="byte[]" 명시하기
  • VO 필드 타입을 byte[]로 맞춤

수정된 코드

<resultMap id="noticeResultMap" type="NoticeVO">
   <result property="sno" column="SNO"/>
   <result property="title" column="TITLE"/>
   <result property="content" column="CONTENT" jdbcType="BLOB">
</resultMap>


<!-- 공지 수정화면 조회 -->
<select id="selectNotice" resultMap="noticeResultMap"  parameterType="NoticeVO">
    SELECT
        A.SNO    AS sno,
        A.TITLE     AS title,
        A.CONTENT      AS content
    FROM TB_NOTI_MGMT A
    WHERE 1=1
    AND A.SNO = #{sno}
</select>

 

🚨에러2

<result property="cont" column="CONT" jdbcType="BLOB" javaType="byte[]"/> 일 때

Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'cont' of 'class NoticeVO' with value '[Ljava.lang.Byte;@64c9ed7' Cause: java.lang.IllegalArgumentException: Unsupported type for cont: class [Ljava.lang.Byte;

 

<result property="cont" column="CONT" jdbcType="BLOB"> 일 때

Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Could not set property 'cont' of 'class NoticeVO' with value 'oracle.sql.BLOB@757bfee0' Cause: java.lang.IllegalArgumentException: Unsupported type for cont: class oracle.sql.BLOB

 

🔥원인

  • MyBatis가 Oracle 드라이버의 oracle.sql.BLOB 객체를 VO의 byte[] cont 필드에 바로 매핑 못함
  • 타입이 달라서 setCont(byte[])에 바로 못 넣음

🛠 해결법

  • MyBatis가 BLOB 데이터를 byte[]로 변환할 수 있도록 typeHandler="org.apache.ibatis.type.BlobTypeHandler" 명시

📖 수정된 코드

<resultMap id="noticeResultMap" type="NoticeVO">
    <result property="sno" column="SNO"/>
    <result property="title" column="TITLe"/>
    <result property="content" column="CONTENT" jdbcType="BLOB" typeHandler="org.apache.ibatis.type.BlobTypeHandler"/>
</resultMap>

 

🚨에러3

Could not set property 'cont' of 'class NoticeVO' with value '[B@300941a7' Cause: java.lang.IllegalArgumentException: argument type mismatch

 

🔥원인

  • MyBatis가 BLOB을 byte[]로 변환해서 넘겼는데,
  • VO의 setCont 메서드 오버로딩(setCont(String), setCont(byte[]))으로 인해 리플렉션에서 어느 메서드 호출할지 혼란 발생
  • 타입 불일치 에러 발생

🛠 해결법

  • setCont(Object cont) 형태로 변경하여, 들어오는 값 타입을 런타임에 체크하고 적절히 처리하도록 구현

📖 수정된 코드

  • getter는 String getCont() 등 필요한 형태로 구현
  • MyBatis가 호출하는 메서드가 명확해져 타입 불일치 문제 해결
public void setContent(Object content) {
    System.out.println("setContent called with type: " + (content == null ? "null" : content.getClass().getName()));
    if (content instanceof byte[]) {
        this.content = (byte[]) content;
    } else if (content instanceof String) {
        this.content = ((String) content).getBytes(StandardCharsets.UTF_8);
    } else if (content == null) {
        this.content = null;
    } else {
        throw new IllegalArgumentException("Unsupported type for content: " + content.getClass());
    }
}



🚨INSERT 에러

### The error may involve adminMapper.insertNotice-Inline

### The error occurred while setting parameters

### SQL: MERGE INTO TB_NOTI_MGMT target          USING (        SELECT             ? AS sno,             ? AS titl,             ? AS cont ) source              ON (target.SNO = ?)          WHEN MATCHED THEN              UPDATE SET                  TITL = source.titl,                  CONT = source.cont          WHEN NOT MATCHED THEN              INSERT (SNO, TITL, CONT)              VALUES (source.sno, source.titl, source.cont)

### Cause: java.sql.SQLException: ORA-01465: 16진수의 지정이 부적합합니다

; uncategorized SQLException; SQL state [72000]; error code [1465]; ORA-01465: 16진수의 지정이 부적합합니다

; nested exception is java.sql.SQLException: ORA-01465: 16진수의 지정이 부적합합니다

 

🛠 해결방법

✅1. vo에 blob(mybatis에서 get), string(프론트에 반환) 타입 필드 각각 추가.

public class NoticeVO {
    private String sno = "";
    private String title = "";
    private byte[] content;
    private byte[] contentBlob;

    public String getContent () {
        // BLOB 데이터를 문자열로 변환 (UTF-8 인코딩 사용)
        if (content != null) {
            return new String(content , StandardCharsets.UTF_8);
        }
        return null;
    }

    public byte[] getContentBlob() {
        return content ;
    }

    public void setContentBlob(byte[] contentBlob ) {
        this.contentBlob = contentBlob;
    }

}

 

✅2. 서비스 단에서 변환하여 삽입.

try {
    String strContent  = inputVO.getContent();
    byte[] blobContent = strContent.getBytes("UTF-8");
    inputVO.setContBlob(blobContent);
} catch(Exception e) {
    logger.error( e.getMessage() );
}

 

<update id="insertNotice" parameterType="NoticeVO">
        MERGE INTO TB_NOTI_MGMT target
        USING (
    SELECT
        #{sno} AS sno,
        #{title} AS title,
        #{contentBlob, jdbcType=BLOB} AS content,
    FROM DUAL
) source   
        ON target.SNO = #{sno}
        WHEN MATCHED THEN
            UPDATE SET
                TITLE = source.title,
                CONTENT = source.content
        WHEN NOT MATCHED THEN
            INSERT ( SNO, TITLE, CONTENT)
            VALUES (source.sno, source.title, source.content)
</update>