[Spring] 7.DAO 구현
DAO
저번 장에서 SqlSessionFactory를 이용하여 Mybatis와 Mysql을 연동하였습니다.
이제는 그 연결을 Spring까지 끌고와서 DAO(Data Access Object)를 구현해보겠습니다.
DAO 는 쉽게 말해서 Mysql 서버에 접근하여 SQL문을 실행할 수 있는 객체입니다.
보통 프로젝트는 SQL문을 XML만을 이용해서 작성해 놓고, DAO가 XML을 찾아서 SQL문을 실행하는 방식을 사용합니다.
그렇게 되면 SQL문은 XML로 별도로 작성되기에 SQL문의 수정이나 유지보수에 적합합니다!
DAO 구현순서
DAO는 다음과 같은 순서로 구현됩니다.
1.MyBatis Mapper 설정 (최초 1회)
2.DB Schema(Table 등) 작성
3.*Mapper.xml 작성
4.도메인 객체 생성 (VO)
5.DAO interface 작성
6.DAO 구현 class 작성
7.테스트
MyBatis Mapper 설정
DAO를 구현하기 위해 설정해야할 것들이 있습니다~!
먼저, Mapper 파일의 저장경로를 설정합니다. Mapper란 MyBatis에서 SQL 문을 저장하는 존재를 말합니다.
Mapper를 저장할 폴더 mappers를 src/main/resources 에 추가해줍니다.
이왕 폴더 추가한거 src/main/java 에 도메인 객체(VO)가 저장될 domain 폴더와 DAO가 저장될 persistence 폴더도 추가해줍니다!
그리고 myBatis가 동작하면 Mapper를 인식할 수 있게 root-context.xml에서 sqlSessionFactory에 다음과 같이 속성을 추가합니다!
<!-- root-context.xml -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="configLocation" value="classpath:/mybatis-config.xml"></property>
<!-- mapperLocations 속성 추가 -->
<property name="mapperLocations" value="classpath:mappers/**/*Mapper.xml"></property>
</bean>
그 다음 SqlSessionTemplate를 설정해야합니다~
SqlSessionTemplate는 개발자들이 DAO와 DB를 직접 연결 맺고, 종료할 필요가 없게 해줍니다!
mybatis-spring에서 제공하는 SqlSessionTemplate은 MyBatis의 SqlSession 인터페이스를 구현한 클래스로,
기본적인 트랜잭션의 관리나 쓰레드 처리의 안정성 등을 보장해주고, 데이터베이스의 연결과 종료를 책임집니다!
엄청난 기능을 하는 클래스죠? 당장 root-context.xml에 추가해줍니다!
<!-- root-context.xml -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"
destroy-method="clearCache">
<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
</bean>
마지막으로 스프링이 DAO가 있는 패키지를 스캔하여 DAO를 빈으로 등록할 수 있게 root-context.xml에 다음을 추가합니다!
<!-- root-context.xml -->
<context:component-scan base-package="io.github.kookyungmin.persistence">
</context:component-scan>
이로써 DAO를 구현하고 테스트 하기 위한 초기 세팅은 끝났습니다!
데이터베이스 테이블 생성
mysql 서버에 접속해서 다음과 같은 테이블을 생성하겠습니다!
CREATE TABLE Member (
userid varchar(50) NOT NULL,
userpw varchar(50) NOT NULL,
username varchar(5) NOT NULL,
email varchar(100) DEFAULT NULL,
regdate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
updatedate timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (userid)
);
이 테이블에 대한 DAO를 생성해서 좀 있다가 SQL문을 실행할 것입니다!
XML Mapper의 작성
아까 Mapper는 SQL문을 저장하는 곳이라고 했죠??
아까 생성한 mappers 폴더에 memberMapper.xml 을 추가해서 실행할 SQL문을 추가해주겠습니다~!
<?xml version="1.0" encoding="UTF-8"?>
<!-- DTD 선언 -->
<!DOCTYPE mapper
PUBLIC "-//mybatis.org/DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="MemberMapper">
<!-- DAO의 메서드가 될 것이다. -->
<!-- 현재 시간 조회 -->
<select id="getTime" resultType="String">
SELECT now()
</select>
<!-- 데이터 삽입 -->
<insert id = "insertMember">
INSERT INTO Member( userid, userpw, username, email)
VALUES(#{userid}, #{userpw}, #{username}, #{email})
</insert>
<!--데이터 조회 -->
<select id="selectMember" resultType="io.github.kookyungmin.domain.MemberVO">
SELECT * from Member
WHERE userid = #{userid}
</select>
</mapper>
구현될 DAO는 이 Mapper.xml에서 SQL문을 찾아 실행할 것입니다~!
눈치채셨겠지만 #{}는 후에 삽입되어 대체될 값입니다~!
예를 들어 나중에 userid가 5로 정해지면 userid = #{userid}는 userid = 5 가 됩니다!
도메인 객체 생성(VO)
도메인 객체(VO)는 특정 테이블과 유사한 속성을 가지는 클래스를 의미합니다~! 쿼리의 결과를 담는 등 데이터를 담기 위해 사용됩니다.
쿼리의 결과나 웹브라우저의 요청은 VO에 담겨 전달됩니다~!(model 이라고 생각)
도메인 객체를 아까 생성한 폴더 io.github.kookyungmin.domain에 생성하겠습니다.
package io.github.kookyungmin.domain;
import java.util.Date;
public class MemberVO {
private String userid;
private String userpw;
private String username;
private String email;
private Date regdate;
private Date updatedate;
public void setUserid(String userid) {
this.userid = userid;
}
public String getUserpw() {
return userpw;
}
public void setUserpw(String userpw) {
this.userpw = userpw;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getUserid() {
return userid;
}
public Date getRegdate() {
return regdate;
}
public void setRegdate(Date regdate) {
this.regdate = regdate;
}
public Date getUpdatedate() {
return updatedate;
}
public void setUpdatedate(Date updatedate) {
this.updatedate = updatedate;
}
}
DAO interface 작성
데이터베이스에 테이블의 구성과 도메인 클래스의 구성이 끝났다면, 실제로 실행해야하는 작업을 인터페이스로 정의합니다!
아까 생성한 io.github.kookyungmin.persistence에 MemberDAO를 추가합니다!
package io.github.kookyungmin.persistence;
import io.github.kookyungmin.domain.MemberVO;
public interface MemberDAO {
public String getTime();
public void insertMember(MemberVO vo);
public MemberVO selectMember(String userid);
}
DAO 구현
MemberDAO 가 인터페이스이기에 이를 구현하는 클래스도 있어야겠죠?
MemberDAOImpl.java 를 생성해줍니다.
package io.github.kookyungmin.persistence;
import javax.inject.Inject;
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
import io.github.kookyungmin.domain.MemberVO;
@Repository //DAO를 스프링에 인식시키기 위해서 사용
public class MemberDAOImpl implements MemberDAO{
@Inject
private SqlSession sqlSession;
private static final String GetTime = "MemberMapper.getTime";
private static final String InsertMember = "MemberMapper.insertMember";
private static final String SelectMember = "MemberMapper.selectMember";
@Override
public String getTime() {
return sqlSession.selectOne(GetTime);
}
@Override
public void insertMember(MemberVO vo) {
sqlSession.insert(InsertMember,vo);
}
@Override
public MemberVO selectMember(String userid) {
return (MemberVO)sqlSession.selectOne(SelectMember,userid);
}
}
위의 코드를 보시면 실질적인 SQL문 호출은 sqlSession(sqlSessionTemplate)이 하시는 것을 볼 수 있습니다!
테스트
정말 기나긴 여정이었습니다! 지금까지 설정하고 생성한것이 제대로 동작하나 테스트해봐야겠죠?
package io.github.kookyungmin;
import javax.inject.Inject;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import io.github.kookyungmin.domain.MemberVO;
import io.github.kookyungmin.persistence.MemberDAO;
//Runner 클래스(테스트 메소드를 실행하는 클래스) 를 SpringJUnit4ClassRunner로 함
@RunWith(SpringJUnit4ClassRunner.class)
//location 속성 경로에 있는 xml 파일을 이용해서 스프링이 로딩됨
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/**/root-context.xml")
public class MemberDAOTest {
//DAO 를 구현한 객체 자동으로 생성
@Inject
private MemberDAO dao;
@Before //@Test 전에 실행
public void testInsertMember() throws Exception{
MemberVO vo = new MemberVO();
vo.setUserid("gguri");
vo.setUserpw("1234");
vo.setUsername("koo");
vo.setEmail("rudals4549@naver.com");
dao.insertMember(vo);
}
@Test
public void testSelectMember() throws Exception{
MemberVO vo = dao.selectMember("gguri");
System.out.println(vo.getUserid()+"/"+vo.getUsername()+"/"
+vo.getEmail());
}
}
올바르게 실행 되었네요!
my sql 서버에도 행이 추가되었나보죠!
제대로 추가되었습니다~!
자! 지금까지 DAO 구현을 해보았는데요~ 처음에 설정하는 것이 복잡했죠!
하지만, 설정한 후에는 정말 간편히 sql 서버에 연동하고 SQL문을 실행할 수 있습니다~!
앞으로 Member 테이블에 접근해서 sql문을 실행시키고 싶으면, Mapper 파일에 sql문을 추가하고,
인터페이스 DAO의 메소드를 추가한 후 그것을 구현만 해주면 됩니다~
그리고 DAO 객체의 메소드를 호출만 하면, SQL문이 실행됩니다!
또 테이블에서 가져오고 쓰는 데이터는 VO에 담겨 전달됩니다.
앞으로 자주 DAO 구현할테니 금방 익숙해지실겁니다~