ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Ktorm] MSSQL "String or binary data would be truncated" 트러블 슈팅 (varchar vs text)
    Java-Kotlin 2026. 1. 21. 10:22
    반응형

    Ktorm docs 메인 이미지

     

    1. 문제 상황

    Kotlin 기반의 ORM인 Ktorm을 사용하여 MSSQL 데이터베이스 마이그레이션 기능을 구현하고 있었습니다. 마이그레이션이 수행될 때마다 실행된 SQL 스크립트 전문(DDL)을 이력 테이블(ddl_dsl_migration_schema)에 저장하는 로직이 있는데, 길이가 긴 CREATE TABLE 스크립트를 저장하는 순간 아래와 같은 에러가 발생하며 프로세스가 중단되었습니다.

    2. 에러 로그

     
    com.microsoft.sqlserver.jdbc.SQLServerException: String or binary data would be truncated in table 'CROSS_POS_DB.dbo.ddl_dsl_migration_schema', column 'script'. 
    Truncated value: 'BEGIN TRANSACTION; IF NOT EXISTS ( SELECT * FROM sys.objects ...'.
    • 핵심 메시지: String or binary data would be truncated
    • 의미: 테이블의 특정 컬럼(script)이 허용하는 길이보다 더 긴 데이터를 넣으려다 잘렸다는 의미입니다.

     

    3. 원인

    로그를 저장하는 테이블의 스키마 정의 코드를 살펴보니, 스크립트를 저장하는 컬럼이 varchar로 정의되어 있었습니다.

    (이 프로젝트의 경우에는 varchar에 length를 따로 안넣어주면 default length가 255이기에, 타입이 varchar(255)로 들어갑니다)
     
    // 문제가 된 코드
    object MigrationSchema : Table<Nothing>("ddl_dsl_migration_schema") {
        // ...
        val script = varchar("script") // 보통 VARCHAR(255) 등으로 매핑됨
        // ...
    }

    Ktorm에서 varchar("name") 함수를 사용하면 기본적으로 길이 제한이 있는 VARCHAR 타입으로 매핑됩니다. 하지만 제가 저장하려던 SQL 스크립트는 트랜잭션 구문과 DDL이 포함되어 있어 이 길이를 훨씬 초과했기 때문에 에러가 발생한 것입니다.

    4. 해결 방법

    MSSQL의 VARCHAR(MAX) 또는 TEXT 타입처럼 대용량 문자열을 저장하기 위해서는 Ktorm의 text() 함수를 사용해야 합니다.

    1) Ktorm 스키마 코드 수정

    varchar를 text로 변경하여 해당 컬럼이 긴 문자열임을 명시했습니다.

     
    // 수정된 코드
    object MigrationSchema : Table<Nothing>("ddl_dsl_migration_schema") {
        // ...
        // val script = varchar("script") -> text()로 변경
        val script = text("script") 
        // ...
    }

    2) DB 컬럼 타입 변경

    코드를 수정해도 이미 생성된 DB 테이블은 자동으로 바뀌지 않습니다. DB 클라이언트에서 직접 컬럼 크기를 늘려주었습니다. (MSSQL 기준)

    SQL
     
    ALTER TABLE [dbo].[ddl_dsl_migration_schema]
    ALTER COLUMN [script] TEXT;

    5. 결과 및 요약

    위와 같이 조치 후 다시 실행하니, 긴 SQL 스크립트도 잘림 없이 정상적으로 이력 테이블에 저장되었습니다.

    • Varchar: 이름, 코드 등 길이가 예측 가능한 짧은 문자열에 사용
    • Text: 로그, 본문, JSON 덤프 등 길이가 긴 문자열에 사용

     

    하지만 좀 더 찾아보니 Text 타입은 항상 blob으로 저장되고, Varchar(max)는 8000바이트 이하면 행에 직접 저장, 그 이상이면 blob으로 저장(Text와 유사)되므로, 일반적으로 Text 타입 대신 Varchar(max)를 사용하는 것을 권장한다는 것을 알았습니다.

     

    이후에 한번 더 ddl-dsl 부분을 만질 일이 생기면 Text타입에 대한 dialect에서의 매칭을 text() 대신 varchar(max)로 넣게 수정할 것입니다.

    댓글

Designed by Tistory.