CoreERP Audit Log 검색 기능 트러블슈팅

최병현·2026년 3월 16일

coreerp project

목록 보기
36/44

Audit Log 조회 페이지에서 검색어 필터가 정상적으로 동작하지 않는 문제가 발생했다. 프론트엔드에서는 정상적으로 keyword 파라미터가 전달되고 있었고, DB에서도 동일한 SQL을 실행하면 결과가 정상적으로 조회되었다.

하지만 Spring Boot 서버에서는 검색 요청 시 예외가 발생하면서 조회가 실패하고 있었다. 서버 로그를 확인한 결과 Hibernate 내부에서 Query 생성 중 예외가 발생하고 있었다.


문제 증상

  • 검색어 입력 후 조회 시 결과가 나오지 않음
  • API 호출 시 서버에서 예외 발생
  • DB에서 직접 실행한 SQL은 정상 동작

서버 에러 로그

Hibernate 로그를 확인하면 다음과 같은 오류가 발생하고 있었다.

FunctionArgumentException: Parameter 1 of function 'lower()' has type 'STRING', 
but argument is of type 'java.lang.String' mapped to 'CLOB' 

즉 Hibernate에서 lower() 함수가 CLOB 타입 컬럼에 적용되면서 쿼리 생성 단계에서 예외가 발생하고 있었다.


원인 분석

AuditLog 엔티티의 detailJson 필드는 다음과 같이 저장되어 있었다.

@Lob
@Column(name = "detail_json")
private String detailJson;

@Lob 가 적용된 String 필드는 Hibernate에서 CLOB 타입으로 매핑된다.

기존 검색 로직에서는 모든 문자열 필드에 lower() 를 적용하고 있었다.

문제가 되었던 코드

Expression<String> descriptionExpr = cb.lower(cb.coalesce(root.get("description"), ""));
Expression<String> usernameExpr = cb.lower(cb.coalesce(root.get("username"), ""));
Expression<String> detailJsonExpr = cb.lower(cb.coalesce(root.get("detailJson"), ""));

하지만 Hibernate 6에서는 CLOB 타입에 lower() 적용이 불가능하다.

따라서 detailJsonlower() 를 적용하는 순간 Hibernate Query 생성 단계에서 예외가 발생하고 결과적으로 검색 API 전체가 실패하고 있었다.


해결 방법

해결 방법은 단순하다.

  • 일반 문자열 컬럼 → lower() 사용
  • CLOB 컬럼(detailJson) → lower() 제거

JSON 내부 검색은 대소문자 구분 없이 대부분 동작하므로 lower() 없이 like 검색만 적용하도록 수정하였다.


수정 코드

String lowerLikeKeyword = "%" + normalizedKeyword + "%";
String rawLikeKeyword = "%" + rawKeyword + "%";

Expression<String> descriptionExpr = cb.lower(cb.coalesce(root.get("description"), ""));
Expression<String> usernameExpr = cb.lower(cb.coalesce(root.get("username"), ""));
Expression<String> ipAddressExpr = cb.lower(cb.coalesce(root.get("ipAddress"), ""));
Expression<String> entityIdExpr = cb.coalesce(root.get("entityId").as(String.class), "");
Expression<String> actionExpr = cb.lower(root.get("action").as(String.class));
Expression<String> entityTypeExpr = cb.lower(root.get("entityType").as(String.class));

Expression<String> detailJsonExpr = cb.coalesce(root.get("detailJson"), "");

predicates.add(
    cb.or(
        cb.like(descriptionExpr, lowerLikeKeyword),
        cb.like(usernameExpr, lowerLikeKeyword),
        cb.like(ipAddressExpr, lowerLikeKeyword),
        cb.like(entityIdExpr, rawLikeKeyword),
        cb.like(actionExpr, lowerLikeKeyword),
        cb.like(entityTypeExpr, lowerLikeKeyword),
        cb.like(detailJsonExpr, rawLikeKeyword)
    )
);

결과

수정 이후 다음과 같은 검색이 정상적으로 동작한다.

  • → 로그인 로그 조회
  • a12312 → 사용자 로그인 로그 조회
  • master → 관리자 로그인 로그 조회
  • 로그 → 로그인 / 로그아웃 기록 조회

정리

  • Hibernate 6에서는 CLOB 타입에 lower() 사용 불가
  • @Lob 필드는 Query Function 사용 시 타입 주의 필요
  • JSON 검색은 like 만으로도 충분히 처리 가능

이번 문제는 검색 로직 자체의 문제가 아니라 Hibernate 타입 처리 방식 변경 때문에 발생한 이슈였다.


느낀 점

단순한 검색 기능처럼 보였지만 ORM 레벨에서의 타입 처리와 Query Function 제약을 이해하지 못하면 예상치 못한 예외가 발생할 수 있다는 것을 다시 한번 확인할 수 있었다.

특히 Hibernate 6에서는 이전 버전보다 Query Function 타입 검사가 훨씬 엄격해졌기 때문에 LOB 컬럼을 다룰 때는 반드시 주의가 필요하다.

profile
Develop

0개의 댓글