Programming/Spring Framework

[SpringBoot] Enum타입을 DB에 변환 저장하는 법

Deveun 2021. 12. 19. 03:40

Mybatis를 사용하여 DB에서 User정보를 가져오는 부분에서 다음과 같은 에러가 발생했다. 

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.executor.result.ResultMapException: Error attempting to get column 'USER_ROLE' from result set....

 

User 클래스에 해당 사용자가 SELLER인지 ORDERER인지를 구분하는 USER_ROLE이라는 Enum을 사용하고 있는데, DB에서는 USER_ROLE을 INTEGER타입으로 저장하고 있기 때문에 값을 불러오는데에서 타입변환 문제가 발생한 것이다.

 

 

- User class

@AllArgsConstructor
@Getter
@Builder
public class User {
    private Long id; // pk
    private String userId; // 회원 아이디
    private String password; // 회원 비밀번호
    private String userName; // 회원 이름
    private String email; // 회원 이메일
    private String phone; // 회원 연락처
    private String si; // 회원 주소 - 시
    private String gu; // 회원 주소 - 구
    private String dong; // 회원 주소 - 동
    private String address; // 회원 주소 - 상세주소
    private UserRole userRole; // 회원 역할 (판매자, 구매자)
}

 

- DB Schema

DROP TABLE IF EXISTS USERS;

CREATE TABLE USERS(
    ID LONG PRIMARY KEY,
    USER_ID VARCHAR(20),
    PASSWORD VARCHAR(20),
    USER_NAME VARCHAR(20),
    EMAIL VARCHAR(30),
    PHONE VARCHAR(11),
    SI VARCHAR(10),
    GU VARCHAR(10),
    DONG VARCHAR(10),
    ADDRESS VARCHAR(20),
    USER_ROLE INT
);

 

User 클래스의 Enum값을 DB에 저장하거나 DB의 값을 꺼내와 User 클래스의 Enum값에 맞게 변환하여 저장하기 위해서는 TypeHandler가 필요하다.

 

1. UserTypeHandler 생성

TypeHandler 인터페이스에는 다음과 같은 메소드들이 선언되어있다.

o class -> db 저장시에 쿼리문에 전달할 변수값을 변경하는 setParameter 메소드

o db -> class 저장시에 객체 파라미터로 변경되어 저장될 값을 구하는 getResult 메소드

 

변환이 필요한 UserRole 타입의 TypeHandler를 implements 하여 다음과 같이 메소드를 구현해주자.

 

- UserRoleTypeHandler.java

@MappedTypes(UserRole.class)
public class UserRoleTypeHandler implements TypeHandler<UserRole> {
    @Override
    public void setParameter(PreparedStatement preparedStatement, int i, UserRole userRole, JdbcType jdbcType) throws SQLException {
        preparedStatement.setInt(i, userRole.getRoleCode());
    }

    @Override
    public UserRole getResult(ResultSet resultSet, String s) throws SQLException {
        final var roleCode = resultSet.getInt(s);
        return getRoleName(roleCode);
    }

    @Override
    public UserRole getResult(ResultSet resultSet, int i) throws SQLException {
        final var roleCode = resultSet.getInt(i);
        return getRoleName(roleCode);
    }

    @Override
    public UserRole getResult(CallableStatement callableStatement, int i) throws SQLException {
        final var roleCode = callableStatement.getInt(i);
        return getRoleName(roleCode);
    }

    private UserRole getRoleName(int roleCode) {

        for (UserRole userRole : UserRole.values()) {
            if (userRole.getRoleCode() == roleCode)
                return userRole;
        }

        return null;
    }
}

 

- UserRole.java

public enum UserRole {
    SELLER(1),
    ORDERER(2);

    @Getter
    private final int roleCode;

    UserRole(int roleCode) {
        this.roleCode = roleCode;
    }

    public static UserRole getRoleName(int roleCode) {
        return Arrays.stream(UserRole.values()).filter(x-> x.getRoleCode() == roleCode)
                .findFirst().orElseThrow(() -> new WrongRoleCodeException());
    }
}

 

2. Mybatis에 TypeHandler 패키지 세팅

application.yml 파일 내에 Mybatis 사용시에 TypeHandler를 사용하기 위해 패키지 경로를 추가로 설정해줘야한다.

mybatis:
	mapper-locations: classpath:mapper/*.xml # mapper.xml 의 경로
	type-handlers-package: com.flab.funding.domain.user.infrastructure  # mybatis 에서 enum 사용을 위한 typeHandler 경로

 

 

 

[참고] https://shlee0882.tistory.com/292