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 경로
'Programming > Spring Framework' 카테고리의 다른 글
[SpringBoot] 공통 Response 포맷 적용하기 (1) | 2022.01.14 |
---|---|
[SpringBoot] Mybatis를 사용한 Service 테스트 코드 작성하기 (0) | 2021.12.18 |
[SpringBoot] PetClinic 샘플 프로젝트 - 빌드 및 실행하기 (0) | 2021.11.14 |