MyBatis-Plus의 TypeHandler는 Java 타입과 JDBC 타입 간 변환을 담당하는 핵심 컴포넌트로, 데이터베이스 컬럼 타입과 Java 객체 속성 타입 불일치 문제를 해결하며 JSON, 열거형, 사용자 정의 객체 등 복합 타입 처리에 필수적입니다.
TypeHandler의 핵심 기능
- 타입 변환 브리징
SQL 실행 시 Java 객체 값을
PreparedStatement에 설정하거나,ResultSet/CallableStatement에서 값을 추출해 Java 타입으로 변환합니다. - 복합 타입 지원 기본 타입(String, Integer 등)은 자동 처리되지만, JSON, 컬렉션, 사용자 정의 타입은 커스텀 핸들러 구현이 필요합니다.
- 유연한 설정 어노테이션 또는 XML 매핑 파일로 필드 단위 핸들러 지정이 가능합니다.
주요 적용 사례
- 타입 불일치 해결
- JSON 문자열을 DB에 저장 → Java의
Map/DTO 변환 - 콤마 구분 문자열 저장 → Java의
Set<String>변환
- 특수 포맷 처리
- 사용자 정의 날짜 형식(
yyyyMMdd↔LocalDate) - 민감 데이터 암호화/복호화
- 열거형 처리
- DB에 열거형
name()또는ordinal()값 저장 → Java 열거형 객체 변환
구현 방법
1. 내장 TypeHandler 활용
EnumOrdinalTypeHandler, EnumNameTypeHandler 등 기본 제공 핸들러 사용 예:
# application.yml 설정
mybatis-plus:
configuration:
default-enum-type-handler: org.apache.ibatis.type.EnumOrdinalTypeHandler
2. 커스텀 TypeHandler 생성
단계 1: TypeHandler 인터페이스 구현
public class StringSetConverter implements TypeHandler<Set<String>> {
@Override
public void setParameter(PreparedStatement stmt, int idx, Set<String> data, JdbcType jdbcType) throws SQLException {
String combined = String.join(";", data);
stmt.setString(idx, combined);
}
@Override
public Set<String> getResult(ResultSet rs, String col) throws SQLException {
String raw = rs.getString(col);
return raw == null ? null : new HashSet<>(Arrays.asList(raw.split(";")));
}
// ResultSet/CallableStatement 오버라이드 생략
}
단계 2: 핸들러 등록
- 어노테이션 방식
@MappedTypes(Set.class)
@MappedJdbcTypes(JdbcType.VARCHAR)
public class StringSetConverter implements TypeHandler<Set<String>> { ... }
- XML 설정 방식
<typeHandlers>
<typeHandler handler="com.example.StringSetConverter"/>
</typeHandlers>
단계 3: 엔티티에 핸들러 연결
@TableField어노테이션
@TableName(autoResultMap = true) // 필수 활성화
public class Member {
@TableField(typeHandler = StringSetConverter.class)
private Set<String> tags;
}
- XML 매핑 파일
<resultMap id="memberMap" type="com.example.Member">
<result column="tags" property="tags" typeHandler="com.example.StringSetConverter"/>
</resultMap>
내장 핸들러 적용 예시
1. JSON 타입 변환
@TableName(autoResultMap = true)
public class Product {
@TableField(typeHandler = JacksonTypeHandler.class)
private Map<String, Object> specs; // JSON ↔ Map 변환
}
<!-- Jackson 의존성 추가 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.15.0</version>
</dependency>
2. 열거형 처리 기법
@EnumValue어노테이션
public enum AccountState {
ENABLED(10), DISABLED(20);
@EnumValue
private final int stateCode;
}
- 커스텀 열거형 핸들러
public class AccountStateHandler implements TypeHandler<AccountState> {
@Override
public void setParameter(PreparedStatement stmt, int idx, AccountState state, JdbcType jdbcType) throws SQLException {
stmt.setInt(idx, state.getStateCode());
}
// 결과 처리 메서드 생략
}
중요 주의사항
autoResultMap활성화@TableField(typeHandler=...)사용 시 엔티티 클래스에@TableName(autoResultMap=true)필수 적용- 성능 고려사항 빈번한 변환 작업 시 JSON 파싱 결과 캐싱 권장
- 스레드 안전성 커스텀 핸들러는 상태 비저장(stateless) 방식으로 설계
- 버전 호환성 MyBatis 3.x와 MyBatis-Plus 3.x 간 TypeHandler 인터페이스 일치 확인