mybatis 공식 : https://mybatis.org/mybatis-3/configuration.html
DB에서의 type과 VO에서의 type이 다를 수 밖에 없는 Enum
EX
DB : tinyint(2)
DTO / VO : ENUM (int형으로 가져오는거 아님)
tb_status DB MySQL
status tinyint(2)
State.enum
public enum Status {
SUCCESS(0, "인증 성공"),
FAIL(1, "인증 실패"),
NOT_VALUE(2, "값이 없음");
private final int code; // 이 code 변수를 mapper에서 씀
private final String description;
Status(int code, String description) {
this.code = code;
this.description = description;
}
}
dto
public class StatusVO {
private Status status; // 이렇듯 ENUM 값을 매핑한다.
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
}
///////////////////////////////// MVC는 생략하겠음 //////////////////////////////////
mapper
<insert id="insertstatus" parameterType="com.test.enum.StatusVO">
INSERT INTO tb_status (
status
) VALUES (
#{status.code}
)
</insert>
.code 하나면 된다. (enum쪽에서 int형을 code라는 변수로 정의했기에 .code인것)
이것의 원리는 모른다..?
https://mybatis.org/mybatis-3/configuration.html
공식문서에도 나와있지 않다. 아시는분은 댓글을 달아주세요?
mapper
<select id="selectStatus" parameterType="hashmap" resultType="com.test.enum.StatusVO">
SELECT
status
FROM
tb_statu AS a
</select>
dto
public class StatusVO {
private Status status; // 이렇듯 ENUM 값을 매핑한다.
// description 을 가져오고 싶으면 (한글설명) 요렇게 get을 해오면 되고
// 그냥 enum값 자체를 가져오고 싶으면 수정하지 않아도 된다.
public String getErrorState() {
return errorState.getDescription();
}
public void setStatus(Status status) {
this.status = status;
}
}
enum의 code값을 이용해서 값을 매핑해줘야 하고, description을 가져와야 하니까 추가
State.enum 에 추가
public int getCode() {
return this.code;
}
public String getDescription() {
return this.description;
}
인터페이스 생성후 implements 시켜줄것
codeEnum.java
public interface CodeEnum {
public int getCode();
}
State.enum
public enum Status implements CodeEnum {
public int getCode();
}
타입핸들러를 생성해보자 (JDBC와 연관되어 있음)
StatusTypeHandler.java
// @MappedTypes : 타입핸드러를 위해 만들어진 어노테이션이다.
// 매핑할 Java 유형을 지정하는 주석입니다
// https://mybatis.org/mybatis-3/apidocs/org/apache/ibatis/type/MappedTypes.html
@MappedTypes(State.class)
public class StateTypeHandler<E extends Enum<E> & CodeEnum> implements TypeHandler<CodeEnum> {
private final Class<E> type;
private final E[] enumConstants;
public StateTypeHandler(Class<E> type) {
if (type == null) {
throw new IllegalArgumentException("type must not be null");
}
this.type = type;
this.enumConstants = type.getEnumConstants();
if(!type.isInterface() && this.enumConstants == null) {
throw new IllegalArgumentException(type.getSimpleName() + " is not");
}
}
@Override
public void setParameter(PreparedStatement ps, int i, CodeEnum parameter, JdbcType jdbcType) throws SQLException {
ps.setInt(i, parameter.getCode());
}
@Override
/*
ResultSet : 데이터베이스를 쿼리하는 문을 실행하여 생성되는 데이터베이스 결과 집합을 나타내는 데이터 테이블/
개체 ResultSet는 현재 데이터 행을 가리키는 커서를 유지합니다. 처음 커서는 첫 번째 행 앞에 위치합니다.
이 next 메서드는 커서를 다음 행으로 이동하고 개체 false 에 더 이상 행이 없을 때 반환되기 때문에
루프에서 결과 집합을 반복하는 데 ResultSet사용할 수 있습니다
*/
public CodeEnum getResult(ResultSet rs, String columnName) throws SQLException {
return getIntCodeEnum(rs.getInt(columnName));
}
@Override
public CodeEnum getResult(ResultSet rs, int columnIndex) throws SQLException {
return getIntCodeEnum(rs.getInt(columnIndex));
}
@Override
/*
CallableStatement 는 ***PreparedStatement를 extends 한다
SQL 문은 미리 컴파일되어 PreparedStatement개체에 저장됩니다. 그런 다음 이 개체를 사용하여 이 문을 여러 번 효율 적으로 실행할 수 있습니다.
새 파일에 따로 저장
*/
public CodeEnum getResult(CallableStatement cs, int columnIndex) throws SQLException {
return getIntCodeEnum(cs.getInt(columnIndex));
}
public CodeEnum getCodeEnum(int code) {
return Arrays.stream(enumConstants)
.filter(o -> o.getCode() == code) // 필터를 통해 여기서 매칭해준다.
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("not" + code + "to" + type.getSimpleName()));
}
}
난 이부분이 아직 어렵다... 열심히 주석을 달아보자 / 공식문서는 요기
https://mybatis.org/mybatis-3/apidocs/org/apache/ibatis/type/TypeHandler.html

마지막 설정부분
mybatis-config.xml
<!-- 타입 핸들러 설정, 타입핸들러 일괄적용 시키기 (패키지) -->
<typeHandlers>
<package name="com.test.test.typehandler"/>
</typeHandlers>
이때 주의해야할 점이 있다. mybatis 설정 xml 파일에선 태그들의 순서를 지켜야 된다.
https://mybatis.org/mybatis-3/ko/configuration.html

PreparedStatement
캐시와 비슷한 느낌이다. 별도로 저장해놓고 다음부터 요청 받으면 재사용하는거
원래 쿼리를 처리할때의 단계 : 쿼리분석 -> 최적화 -> 권한체크 -> 쿼리 실행
프리페어 스테이트먼트를 하면? 쿼리분석 -> 최적화을 한번만 실행하고 따로 저장해둠 (즉 속도가 빨라짐)
ex ) selece * from status where state=1.....하며 state=100 까지 100개의 쿼리를 조회한다고 치자. 이 얼마나 비효율적인 방식이냐 이를 위해 state=#{state}가 나오게 된것이다. 이게 PreparedStatement
PreparedStatement pstmt = con.prepareStatement("UPDATE EMPLOYEES
SET SALARY = ? WHERE ID = ?");
pstmt.setBigDecimal(1, sal);
pstmt.setInt(2, 110592); // INTEGER메소드를 setInt사용