Springboot에서 Mybatis 사용하기
DB 연결
사용하려는 DB에 대한 의존성을 추가하고 db 관련 프로퍼티를 설정하면 쉽게 연동할 수 있다.
dependency 추가
연결하는 것이 목적이기 때문에 가벼운 h2 데이터베이스를 사용했다.<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency>
DataSource 설정
어플리케이션 프로퍼티 파일(application.yml or application.properties)에 DataSource를 설정한다.
springboot는 connection pool로써 hikariCP를 디폴트로 사용하지만 TomcatCP, Commons DBCP2도 지원한다.
** datasource는 db connection을 관리하는 객체이고 이를 위해 자체적으로 CP기능을 구현하고 있다.#application.yml spring: datasource: url: jdbc:h2:tcp://localhost/~/test # db url driver-class-name: org.h2.Driver # db driver 생략해도 url 형태를 보고 자동으로 찾아줌 username: sa password: schema: schema.sql # ddl file hikari: # ConnectionPool 설정 maximum-pool-size=4
** springboot에서 datasource url를 설정하지 않으면 자동으로 h2 인메모리 DB로 동작
** resource 루트(src/main/resources)에 schema.sql, data.sql 파일로 어플리케이션 시작 시 적용될 DDL 스크립트와 DML 스크립트를 작성할 수 있다. ( 파일 이름은 application.yml에서 변경 가능)//schema.sql drop table if exists Post; drop table if exists Member; create table Member ( member_id int primary key auto_increment, user_id varchar(50) unique, name varchar(50) not null, password varchar(50) not null ); create table Post ( post_id INT primary key auto_increment, member_id int not null, content varchar(255), foreign key (member_id) references Member(member_id), created_at datetime not null default current_timestamp );
//data.sql insert into member(user_id, name, password) values('aaa','bespoke','1234');
Mybatis 설정
- dependency 추가
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.3</version>
</dependency>
- mybatis property 설정
#application.yml
mybatis:
mapper-location: mapper/**/*.xml # Mybatis mapper.xml 위치 설정
type-aliases-package: org.example.demo.rest.domain #mapper에서 resultType 간략하게
configuration:
map-underscore-to-camel-case=true #java vo 클래스의 카멜케이서를 언더스코어로 바꾸어줌
mybatis.mapper-location
: mapper xml 파일의 위치를 설정.type-aliases-package
: mapper 파일에서 mapping Type의 alias를 지정configuration.map-underscore-to-camel-case
: java domain(vo,dto) 클래스의 필드의 카멜 케이스 표기 방식을 db table의 underscore방식의 표기 방식과 매핑해준다.
Mapper 구성
3가지 방식으로 mapper를 사용할 수 있다.
mapper xml + DAO pattern
mapper xml + Mapper interface
annotation + Mapper interface
3번째 방법의 경우는 xml로 매퍼를 따로 작성하지 않고 메서드 어노테이션에서 sql를 작성한다.
Model 작성
domain ~ vo ~ model
@Data
@NoArgsConstructor
@RequiredArgsConstructor
public class Member {
private Long memberId;
@NonNull private String userId;
@NonNull private String name;
@NonNull private String password;
}
*Mapper.xml 작성
(3번 방식에서는 생략)
<?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="org.example.demo.rest.repository.MemberMapper">
<insert id="save" parameterType="Member" useGeneratedKeys="true" keyProperty="memberId">
INSERT INTO MEMBER (
user_id
, name
, password
) values (
#{userId}
, #{name}
, #{password})
</insert>
<select id="findOneById" resultType="Member" parameterType="Member">
SELECT *
FROM member
WHERE member_id = #{memberId}
</select>
<select id="findAll" resultType="Member">
SELECT *
FROM member
</select>
</mapper>
type-aliases-package 옵션으로 인해 resultType을 간략하게 표기할 수 있다.(org.example.demo.rest.domain.Member → member)
mapper 등록
xml, java 설정에서 bean으로 등록 - 하나씩 다 등록해야함
매퍼 스캔 : 클래스 패스를 등록해서 자동 등록xml →
<mybatis:scan/>
, java →@MapperScan
@Mapper 어노테이션 : mapper interface에 @Mapper 어노테이션을 붙이면 자동으로 등록 (spring boot에서 지원)
저는 @Mapper 어노테이션 방식을 사용 했습니다.
Mapper 사용
앞서 말한 3가지 방식으로 매퍼를 사용 할 수 있다.
Dao pattern
SqlSession 객체를 통해 sql을 직접 실행한다.
@Repository
@RequiredArgsConstructor
public class MemberDao {
private final SqlSession sqlSession; // spring-mybatis 모듈의 구현체인 SqlSessionTemplate를 사용
public List<Member> selectList(){
return sqlSession.selectList("org.example.demo.rest.repository.MemberMapper.findAll");
}
}
mapper interface
mapper interface는 단순히 매퍼 xml상의 id와 메서드명을 일치시켜주면 된다.
@Mapper
public interface MemberMapper {
public List<Member> findAll();
}
annotation
xml 파일 없이 인터페이스 메서드 어노테이션으로 쿼리를 작성
** java 모델 객체의 필드 명과 db table의 컬럼 명이 일치하지 않아 매핑을 해줘야 한다. configuration.map-underscore-to-camel-case
옵션을 주면 자동으로 변환해서 매핑해준다.
@Mapper
public interface MemberMapper {
@Insert("insert into Member(user_id, name, password) values(#{userId},#{name},#{password})")
@Options(useGeneratedKeys = true, keyProperty = "memberId")
public int save(Member member);
@Select("select * from Member where member_id = #{memberId}")
// @Results({
// @Result(property = "memberId", column = "member_id"),
// @Result(property = "userId", column = "user_id")
// })
public Member findOneById(Long memberId);
@Select("select * from Member")
public List<Member> findAll();
}
Controller에서 Mapper 사용
간단한 curd는 mapper interface를 직접 호출해서 사용하고
로직이 필요한경우 service 클래스 만든다.
@Service
@Transactional
@RequiredArgsConstructor
public class MemberService {
private final MemberMapper memberMapper;
public Long join(Member member){
memberMapper.save(member);
}
}
Springboot에서 mybatis unit test하기
springboot에서 mybatis unit테스트를 할 때는 @MybatisTest
어노테이션을 사용하면된다.
Mapper interface 방식(2,3번)은 @MybatisTest을 사용하면 autowired가 동작하지만 dao 방식은 해당 dao class를 추가로 import 해줘야 한다.
dao test
@RunWith(SpringRunner.class)
@MybatisTest //spring boot - mybatis test
@Import(MemberDao.class)
public class MemberDaoTest {
@Autowired
private MemberDao memberDao;
}
mapper interface test
@RunWith(SpringRunner.class)
@MybatisTest
public class MemberMapperTest {
@Autowired
private MemberMapper memberMapper;
@Test
public void save_find_Test(){
Member member = new Member("a","bbb","1234");
memberMapper.save(member);
Member findMember = memberMapper.findOneById(member.getId());
Assert.assertEquals(saveId,findMember.getMemberId());
}
}
@WebMvcTest 처럼 다른 Test 어노테이션과 같이 쓸 때는 @MybatisTest가 아닌 @AutoConfigureMybatis 사용하기
MyBatis-Spring-Boot-Starter-Test mybatis 공식문서
http://mybatis.org/spring-boot-starter/mybatis-spring-boot-test-autoconfigure/
다음에는 REST와 springboot에서 REST API를 만드는 것을 포스팅 하겠습니다
댓글