객체 지향 언어인 자바의
관계형 데이터베이스 프로그래밍을
좀 더 쉽게 할 수 있게 도와 주는 개발 프레임 워크.
JDBC를 통해 데이터베이스에 엑세스하는 작업을 캡슐화하고
일반 SQL 쿼리, 저장 프로 시저 및 고급 매핑을 지원하며
모든 JDBC 코드 및 매개 변수의 중복 작업을 제거한다.
Mybatis에서는
프로그램에 있는 SQL쿼리들을
한 구성파일에 구성하여
프로그램 코드와 SQL을 분리할 수 있는 장점을 가지고 있다.
복잡한 쿼리나 다이나믹한 쿼리에 강하다
프로그램 코드와 SQL 쿼리의 분리로 코드의 간결성 및 유지보수성 향상
resultType, resultClass등 Vo를 사용하지 않고
조회결과를 사용자 정의 DTO, MAP 등으로 맵핑하여 사용 할 수 있다.
maria db를 사용해서 MyBatis를 학습하기 위해 의존성을 추가해서 프로젝트를 만들었다.
@Mapper
public interface TestMapper {
@Select("SELECT * FROM TB_TEST WHERE idx = #{idx}")
TestDto findByState(@Param("idx") int idx);
@Select("SELECT * FROM TB_TEST ")
List<TestDto> findAll();
}
@Getter
@Setter
public class TestDto {
int idx;
}
public interface TestService {
TestDto findByState(@Param("idx") int idx);
List<TestDto> findAll();
}
@AllArgsConstructor
@Service
public class TestServiceimpl implements TestService {
TestMapper testMapper;
@Override
public TestDto findByState(int idx) {
return testMapper.findByState(idx);
}
@Override
public List<TestDto> findAll() {
return testMapper.findAll();
}
}
@AllArgsConstructor
@RestController
public class TestController {
TestService service;
@GetMapping("/")
public List<TestDto> get1() {
return service.findAll();
}
@GetMapping("/{idx}")
public TestDto get2(@PathVariable int idx) {
return service.findByState(idx);
}
}
@Mapper
public interface TestXmlMapper {
TestDto findByState(@Param("idx") int idx);
List<TestDto> findAll();
}
src/main/resources/mapper
src/main/resources 하위에 mapper 폴더를 만든다음
mapper 폴더 하위에 mapper.xml 파일을 생성한다.
여기서 주의할 점은
TestXmlMapper 인터페이스에 작성한 메서드 이름과
SQL 쿼리 id의 값을 똑같이 작성해주어야 한다는 것이다.
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kim.zhyn.mybatis.mapper.TestXmlMapper">
<select id="findAll" resultType="kim.zhyn.mybatis.dto.TestDto">
select * from tb_test
</select>
<select id="findByState" resultType="kim.zhyn.mybatis.dto.TestDto">
SELECT *
FROM TB_TEST
WHERE idx = #{idx}
</select>
</mapper>
mybatis:
mapper-locations: classpath:mapper/*.xml
스프링 부트에서 classpath의 위치는 src/main/resources
이다.
classpath:mapper/*.xml
는
src/main/resources 폴더 하위에 있는
mapper 폴더의 모든 xml 파일이 해당됨을 의미한다.
@Select("SELECT test.idx, " +
"test.description, " +
"user.name " +
" FROM TB_TEST test " +
"INNER JOIN TB_USER user " +
" USING (idx)")
List<TestWithUserDto> findAllJoinId();
SQL만을 위한 클래스 파일을 별도로 작성해서 사용하는 방법이 있다.
public class TestSql {
public static final String ALL_TEST_WITH_USER =
"SELECT test.idx, " +
"test.description, " +
"user.name " +
" FROM TB_TEST test " +
"INNER JOIN TB_USER user " +
" USING (idx)";
public String findByJoinId(int idx) {
StringBuilder sql = new StringBuilder(ALL_TEST_WITH_USER);
if (idx > -1) {
sql
.append("where idx = ")
.append(idx);
}
return sql.toString();
}
}
@Select(TestSql.ALL_TEST_WITH_USER)
List<TestWithUserDto> findAllJoinId();
@SelectProvider(type = TestSql.class , method = "findByJoinId")
TestWithUserDto findByJoinId(int idx);
동적 쿼리가 필요할 때는 @oooProVider 어노테이션을 사용할 수 있다.
@oooProVider 어노테이션은
매개변수로 type
과 method
를 입력받는다.
type
= sql 클래스를 TestSql.class
형식으로 입력
method
= sql 클래스 파일 안에서 사용 될 메서드 이름을 적어주면 된다.
자바 파일과의 구분을 위해
User 테이블에 Test 테이블을 조인 시킨 구조로 작성하였다.
@Data
@Component
public class UserDto {
int idx;
String name;
// xml mapper에서 사용
private TestDto testDto;
}
@Data
@Component
public class TestDto {
int idx;
String description;
}
<mapper namespace="kim.zhyn.mybatis.mapper.TestXmlMapper">
<resultMap type="kim.zhyn.mybatis.dto.TestDto" id="TestDto">
<result column="idx" property="idx" />
<result column="description" property="description" />
</resultMap>
<resultMap type="kim.zhyn.mybatis.dto.UserDto" id="UserWithTest">
<result column="idx" property="idx" />
<result column="name" property="name" />
<collection property="testDto" resultMap="TestDto" />
<!-- ☝️여기서 property 값은 UserDto 클래스에 생성한 변수이름임. -->
</resultMap>
<select id="findAllJoinId" resultMap="UserWithTest">
SELECT test.idx,
test.description,
user.name
FROM TB_TEST test
INNER JOIN TB_USER user
USING (idx)
</select>
<select id="findByJoinId" resultMap="UserWithTest">
SELECT test.idx,
test.description,
user.name
FROM TB_TEST test
INNER JOIN TB_USER user
USING (idx)
WHERE idx = #{idx}
</select>
</mapper>