5. <set> 엘리먼트의 활용
프로젝트 정보를 변경하는 기능에 대해서도 동적 SQL을 적용해본다. 지금까지는 한 개의 항목을 바꾸더라도 전체 항목을 변경해야 했다. 다음은 프로젝트 정보를 변경하는 UPDATE문이다. 현재는 프로젝트 정보를 변경할 때 이 SQL문을 실행하고 있다.
UPDATE PROJECTS
SET PNAME = #{title}
,CONTENT = #{content}
,STA_DATE = #{startDate}
,END_DATE = #{endDate}
,STATE = #{state}
,TAGS = #{tags}
WHERE PNO = #{no}
이 UPDATE문의 문제는 프로젝트 제목(title)만 변경하고 싶어도 내용, 시작일, 종료일, 상태, 태그까지 변경해야 한다는 것이다. 이 문제를 해결하기 위해 변경하는 상황을 모두 고려하여 UPDATE문을 만든다면 그 경우의 수가 너무 많다. 한 개의 컬럼만 변경하는 경우(6가지)에서 모든 컬럼을 변경하는 경우(1가지)까지 계산해 보면 총 63가지가 나온다. 즉 63개의 UPDATE문을 만들어야 한다. 이것은 오히려 개발을 더욱 복잡하게 만든다.
다음은 컬럼을 변경하는 경우의 수를 구하는 공식이다. 수학에서 나오는 조합(Combination)을 이용하였다(그림 1).
바로 이런 상황일 때 동적 SQL이 필요한 것이다. mybatis의 동적 SQL을 이용하면 63개의 SQL문을 만드는 대신 단 한 개의 SQL문만으로 모두 처리할 수 있다. 다음의 지시에 따라 UPDATE문을 변경한다.
spms.dao 패키지의 MySqlProjectDao.xml 파일을 열고, 프로젝트를 변경하는 SQL문을 찾아 다음과 같이 편집한다.
<update id="update" parameterType="project">
UPDATE PROJECTS
<set>
<if test="title != null">PNAME = #{title},</if>
<if test="content != null">CONTENT = #{content},</if>
<if test="startDate != null">STA_DATE = #{startDate},</if>
<if test="endDate != null">END_DATE = #{endDate},</if>
<if test="state != null">STATE = #{state},</if>
<if test="tags != null">TAGS = #{tags}</if>
</set>
WHERE PNO = #{no}
</update>
parameterType 속성을 "project"에서 "map"으로 바꾸었다. 앞으로는 변경할 값을 Project 객체가 아닌 Map 객체에 담아야 한다. 그리고 SET절 자리에 <set> 태그를 작성하였다.
- <set> 엘리먼트
<set> 태그는 SET절을 만든다. test의 값이 참이면 <if> 태그의 콘텐츠를 반환한다. 예를 들어 title과 startDate의 값이 null이 아니면 다음의 SET절이 만들어 진다.
SET PNAME = '변경한제목', STA_DATE = '변경한날짜'
mybatis는 SET절의 끝에 콤마(,)가 있으면 제거한다. 따라서 STA_DATE 항목에 붙은 콤마(,)가 제거된다.
6. MySqlProjectDao 클래스 변경
UPDATE문이 변경되었기 때문에 이에 맞추어 DAO 클래스도 변경해야 한다.
spms.dao 패키지에서 MySqlProjectDao 클래스를 열고 다음과 같이 update() 메서드를 변경한다.
/**
* 프로젝트 수정
* @param project
* @return count
*/
public int update(Project project) throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
Project original = sqlSession.selectOne("spms.dao.ProjectDao.selectOne", project.getNo());
Hashtable<String,Object> paramMap = new Hashtable<String,Object>();
if(!project.getTitle().equals(original.getTitle())) {
paramMap.put("title", project.getTitle());
}
if(!project.getContent().equals(original.getContent())) {
paramMap.put("content", project.getContent());
}
if(project.getStartDate().compareTo(original.getStartDate()) != 0) {
paramMap.put("startDate", project.getStartDate());
}
if(project.getEndDate().compareTo(original.getEndDate()) != 0) {
paramMap.put("endDate", project.getEndDate());
}
if(project.getState() != original.getState()) {
paramMap.put("state", project.getState());
}
if(!project.getTags().equals(original.getTags())) {
paramMap.put("tags", project.getTags());
}
if(paramMap.size() > 0) {
paramMap.put("no", project.getNo());
//update() : 두 번째 매개변수로 프로젝트 정보 담은 값 객체 전달
//int count = sqlSession.update("spms.dao.ProjectDao.update", project);
int count = sqlSession.update("spms.dao.ProjectDao.update", paramMap);
//임시 데이터베이스에 보관된 작업 결과를 운영 데이터베이스에 적용
sqlSession.commit();
return count;
}else {
return 0;
}
} finally {
sqlSession.close();
}
}
먼저 원래의 프로젝트 정보를 가져온다. 이 값과 사용자가 입력한 값을 비교할 것이다.
Project original = sqlSession.selectOne("spms.dao.ProjectDao.selectOne", project.getNo());
UPDATE문에 전달할 Map 객체를 준비한다. 원래의 값과 사용자가 입력한 값을 비교하여 값이 바뀌었다면 Map 객체에 저장한다.
Hashtable<String,Object> paramMap = new Hashtable<String,Object>();
if(!project.getTitle().equals(original.getTitle())) {
paramMap.put("title", project.getTitle());
}
Map 객체에 저장된 값이 있다면, 즉 변경된 값이 있다면 UPDATE문을 실행한다. 없다면 0을 반환한다.
if(paramMap.size() > 0) {
paramMap.put("no", project.getNo());
//update() : 두 번째 매개변수로 프로젝트 정보 담은 값 객체 전달
//int count = sqlSession.update("spms.dao.ProjectDao.update", project);
int count = sqlSession.update("spms.dao.ProjectDao.update", paramMap);
//임시 데이터베이스에 보관된 작업 결과를 운영 데이터베이스에 적용
sqlSession.commit();
return count;
}else {
return 0;
}
7. 동적으로 생성된 UPDATE문 확인
톰캣 서버를 재시작한다. 웹 브라우저에서 http://localhost:9999/web07/project/list.do를 요청한다. 그리고 프로젝트 목록에서 변경할 항목을 클릭한다(그림 2).
프로젝트 정보 페이지에서 제목과 시작일을 변경하고, <저장> 버튼을 클릭한다(그림 3, 그림 4).
이클립스 콘솔창에 출력된 내용을 확인해본다. 다음은 UPDATE문을 실행할 때 출력된 로그이다(그림 5).
동적 SQL로 만든 UPDATE문을 보면 SET절의 항목이 PNAME과 STA_DATE이다.
UPDATE PROJECTS SET PNAME = ?, STA_DATE = ? WHERE PNO = ?
즉 사용자가 변경한 제목과 시작일만 SET절에 추가되었다. 또한, 로그 내용에는 각 입력 매개변수에 들어갈 값도 포함하고 있다. 사용자가 변경한 제목과 시작일의 값이 보인다.
Parameters: hello!(String), 2022-02-15(Date), 4(Integer)
이렇게 mybatis의 동적 SQL 기능을 이용하면 하나의 SQL문으로 다양한 상황을 처리할 수 있어 매우 편리하다. 그리고 로그 출력 기능을 켜 놓으면 내부에서 진행되는 상황을 살펴볼 수 있어 개발에 많은 도움이 된다.
참고도서 : https://freelec.co.kr/book/1674/
[열혈강의] 자바 웹 개발 워크북
[열혈강의] 자바 웹 개발 워크북
freelec.co.kr
'교재 실습 > 자바 웹 개발 워크북' 카테고리의 다른 글
120. 퍼시스턴스 프레임워크의 도입 정리 (0) | 2022.09.26 |
---|---|
119. 실력 향상 훈련 (2) | 2022.09.25 |
117. 동적 SQL의 사용 (4) (0) | 2022.09.21 |
116. 동적 SQL의 사용 (3) (2) | 2022.09.20 |
115. 동적 SQL의 사용 (2) (1) | 2022.09.19 |
댓글