<< 학습 목표 >>

1. 다양한 형태의 값을 쿼리에 사용할 수 있다.


전 글 ( https://codingaja.tistory.com/115 ) 에서 쿼리에 필요한 값들을 DAO의 매개변수로 넘겨 사용했었음

 

이번에는 간단하지만 파라미터를 사용하는 다섯 가지 방법을 배워보자

1. #{param1}, #{param2}, #{param3} ... 처럼 #{param숫자} 로 파라미터를 사용할 수 있음

2. #{0}, #{1}, #{2} ... 처럼 #{숫자} 로 파라미터를 사용할 수 있음

3. @Param 어노테이션을 사용해 #{ } 안에 사용할 파라미터 명을 직접 지정할 수 있음

4. 해시맵의 키를 #{ } 안에 사용할 수 있음

5. DTO의 멤버 변수명을 #{ } 안에 사용할 수 있음


여기서 사용할 테이블, 쿼리, DAO, 컨트롤러는 모두 전 글까지 사용했던 것들을 사용할 것임

테이블 : Member 테이블

쿼리 : Member.xml 파일 내 INSERT, SELECT

컨트롤러 : MyBatisController

 

전 글에서는 파라미터를 사용하는 가장 나은 방법인 DTO를 사용했지만 이번에는 다양한 방법을 배우는 것이므로 1 ~ 4번 방법을 배울 때는 DTO가 빠짐


방법1. #{param1}, #{param2}, #{param3} ... 처럼 #{param숫자}

 

1. Member.xml 파일을 복사하고 파일명은 Member1 로 지정하자

 

Member1.xml 파일 내 코드를 아래와 같이 바꾸자

<?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="com.study.chapter04.MemberDao1">
	<insert id="insertMember">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{param1}, #{param2}, #{param3}, #{param4});
	</insert>

	<select id="selectMember" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{param1};
	</select>
</mapper>

<< 코드 설명 >>

Member1.xml 파일 내 쿼리는 INSERT 쿼리(2)와 SELECT 쿼리(3)임

파라미터를 사용하는 방법이므로 SELECT 쿼리는 파라미터가 있는 닉네임으로 회원 정보 조회 SELECT 쿼리임

 

여기서 주의할 점은 이 쿼리 파일과 연결될 DAO는 com.study.chapter04 패키지 내 MemberDao1 임(1)

 

 

2. 쿼리 파일과 연결될 DAO를 추가하자

  DAO도 간단하게 복사하자

  com.study.chapter04 패키지 내 MemberDao 를 복사하고 인터페이스명은 MemberDao1 로 지정하자

 

MemberDao1 내 코드를 아래와 같이 바꾸자

package com.study.chapter04;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MemberDao1 {
	void insertMember(String id, String pw, String nickname, String tel);
	SelectMemberDto selectMember(String nickname);
}

<< 코드 설명 >>

- insertMember 메서드 : Member1.xml 파일 내 id 속성이 insertMember인 쿼리로 넘겨주는 파라미터는 총 4개임

  Member1.xml 파일 내 id 속성이 insertMember인 쿼리에서는 DAO가 전달하는 id 매개변수를 #{param1} 로 접근할 수 있고 pw 매개변수는 #{param2} 로 접근할 수 있음

  나머지 nickname, tel도 이와 같은 방식으로 접근할 수 있음

 

 - selectMember 메서드 : Member1.xml 파일 내 id 속성이 selectMember인 쿼리로 넘겨주는 파라미터는 총 1개임

  Member1.xml 파일 내 id 속성이 selectMember인 쿼리에서는 DAO가 전달하는 nickname 매개변수를 #{param1} 로 접근할 수 있음 ( 그림은 생략 )

 

 

3. DAO를 통해 DB와 통신할 컨트롤러를 추가하자

  컨트롤러 역시 간단하게 복사하자

  com.study.chapter04 패키지 내 MyBatisController를 복사하고 컨트롤러명은 MyBatisController1 로 지정하자

 

MyBatisController1 내 코드를 아래와 같이 바꾸자

package com.study.chapter04;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MyBatisController1 {
	@Autowired
	private MemberDao1 memberDao;
	
	@GetMapping("/chapter04/mybatis/v1/member")
	public void getMemberByNickname(String nickname) {
		System.out.println("<< 닉네임으로 회원 정보 조회 시작 >>");
		
		// 닉네임으로 회원 정보 조회
		SelectMemberDto member = memberDao.selectMember(nickname);
		
		// 조회한 회원 정보 출력
		System.out.println(member);
		
		System.out.println("<< 닉네임으로 회원 정보 조회 종료 >>");
	}
	
	@PostMapping("/chapter04/mybatis/v1/member")
	public void insertMember(InsertMemberDto newMember) {
		System.out.println("<< 회원 가입 시작 >>");
		
		String id = newMember.getId();
		String pw = newMember.getPw();
		String nickname = newMember.getNickname();
		String tel = newMember.getTel();

		// 회원 가입
		memberDao.insertMember(id, pw, nickname, tel);
		
		System.out.println("<< 회원 가입 성공 >>");
	}
}

<< 코드 설명 >>

컨트롤러에서 큰 변화는 없으니 주의만 하면 됨

(1). 사용할 DAO 인터페이스명을 MemberDao1 으로 바꾸자

(2). 컨트롤러간 URL이 충돌하지 않도록 URL의 중간에 v1 경로를 추가하자

(3). 이제 회원 가입을 할 때 DTO로 가입할 회원의 정보를 넘기는 방식이 아니므로 지금의 방식에 맞게 가입할 회원의 정보를 넘겨주기 위해서 id ~ tel까지 모두 꺼냄

(4). 가입할 회원의 정보를 DAO로 전달, DAO는 쿼리로 전달, 쿼리는 전달 받은 가입할 회원의 정보를 #{param1} ~ #{param4} 로 접근

이제 서버를 시작하고 회원 가입, 회원 정보 조회를 해보며 #{param1}, #{param2}, #{param3} ... 처럼 #{param숫자} 로 파라미터를 사용하는 방식이 제대로 동작하는지 확인해보자


방법2. #{0}, #{1}, #{2} ... 처럼 #{숫자}

 

1. Member1.xml 쿼리 파일을 복사하고 파일명을 Member2.xml 로 지정하자

<?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="com.study.chapter04.MemberDao2">
	<insert id="insertMember">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{0}, #{1}, #{2}, #{3});
	</insert>

	<select id="selectMember" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{0};
	</select>
</mapper>

 

2. MemberDao1 DAO를 복사하고 인터페이스명을 Member2 로 지정하자

package com.study.chapter04;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MemberDao2 {
	void insertMember(String id, String pw, String nickname, String tel);
	SelectMemberDto selectMember(String nickname);
}


3. MyBatisController1 컨트롤러를 복사하고 컨트롤러명을 MyBatisController2 로 지정하자

package com.study.chapter04;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MyBatisController2 {
	@Autowired
	private MemberDao1 memberDao;
	
	@GetMapping("/chapter04/mybatis/v2/member")
	public void getMemberByNickname(String nickname) {
		System.out.println("<< 닉네임으로 회원 정보 조회 시작 >>");
		
		// 닉네임으로 회원 정보 조회
		SelectMemberDto member = memberDao.selectMember(nickname);
		
		// 조회한 회원 정보 출력
		System.out.println(member);
		
		System.out.println("<< 닉네임으로 회원 정보 조회 종료 >>");
	}
	
	@PostMapping("/chapter04/mybatis/v2/member")
	public void insertMember(InsertMemberDto newMember) {
		System.out.println("<< 회원 가입 시작 >>");
		
		String id = newMember.getId();
		String pw = newMember.getPw();
		String nickname = newMember.getNickname();
		String tel = newMember.getTel();

		// 회원 가입
		memberDao.insertMember(id, pw, nickname, tel);
		
		System.out.println("<< 회원 가입 성공 >>");
	}
}

 

쿼리 파일, DAO, 컨트롤러 모두 설명이 필요 없을 정도로 간단하므로 여러분이 직접 방법1과 방법2를 비교해 공통점과 차이점을 찾아 익혀보자


방법3. @Param 어노테이션

 

1. Member1.xml 쿼리 파일을 복사하고 파일명을 Member3.xml 로 지정하자

<?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="com.study.chapter04.MemberDao3">
	<insert id="insertMember">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{newMemberId}, #{newMemberPw}, #{_nickname}, #{TEL});
	</insert>

	<select id="selectMember" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{nickname};
	</select>
</mapper>

 

2. MemberDao1 DAO를 복사하고 인터페이스명을 Member3 로 지정하자

package com.study.chapter04;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;

@Mapper
public interface MemberDao3 {
	void insertMember(@Param("newMemberId") String id, @Param("newMemberPw")String pw, @Param("_nickname") String nickname, @Param("TEL") String tel);
	SelectMemberDto selectMember(@Param("nickname") String nickname);
}


3. MyBatisController1 컨트롤러를 복사하고 컨트롤러명을 MyBatisController3 로 지정하자

package com.study.chapter04;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MyBatisController3 {
	@Autowired
	private MemberDao3 memberDao;
	
	@GetMapping("/chapter04/mybatis/v3/member")
	public void getMemberByNickname(String nickname) {
		System.out.println("<< 닉네임으로 회원 정보 조회 시작 >>");
		
		// 닉네임으로 회원 정보 조회
		SelectMemberDto member = memberDao.selectMember(nickname);
		
		// 조회한 회원 정보 출력
		System.out.println(member);
		
		System.out.println("<< 닉네임으로 회원 정보 조회 종료 >>");
	}
	
	@PostMapping("/chapter04/mybatis/v3/member")
	public void insertMember(InsertMemberDto newMember) {
		System.out.println("<< 회원 가입 시작 >>");
		
		String id = newMember.getId();
		String pw = newMember.getPw();
		String nickname = newMember.getNickname();
		String tel = newMember.getTel();

		// 회원 가입
		memberDao.insertMember(id, pw, nickname, tel);
		
		System.out.println("<< 회원 가입 성공 >>");
	}
}

방법4. 해시맵

 

1. Member1.xml 쿼리 파일을 복사하고 파일명을 Member4.xml 로 지정하자

<?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="com.study.chapter04.MemberDao4">
	<insert id="insertMember">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{item1}, #{item2}, #{nickname}, #{tel});
	</insert>

	<select id="selectMember" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{key};
	</select>
</mapper>

 

2. MemberDao1 DAO를 복사하고 인터페이스명을 Member4 로 지정하자

package com.study.chapter04;

import java.util.Map;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MemberDao4 {
	void insertMember(Map<String, String> newMember);
	SelectMemberDto selectMember(Map<String, String> filter);
}


3. MyBatisController1 컨트롤러를 복사하고 컨트롤러명을 MyBatisController4 로 지정하자

package com.study.chapter04;

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MyBatisController4 {
	@Autowired
	private MemberDao4 memberDao;
	
	@GetMapping("/chapter04/mybatis/v4/member")
	public void getMemberByNickname(String nickname) {
		System.out.println("<< 닉네임으로 회원 정보 조회 시작 >>");
		
		Map<String, String> filter = new HashMap<>();
		filter.put("key", nickname);
		
		// 닉네임으로 회원 정보 조회
		SelectMemberDto member = memberDao.selectMember(filter);
		
		// 조회한 회원 정보 출력
		System.out.println(member);
		
		System.out.println("<< 닉네임으로 회원 정보 조회 종료 >>");
	}
	
	@PostMapping("/chapter04/mybatis/v4/member")
	public void insertMember(InsertMemberDto newMember) {
		System.out.println("<< 회원 가입 시작 >>");
		
		Map<String, String> filter = new HashMap<>();
		filter.put("item1", newMember.getId());
		filter.put("item2", newMember.getPw());
		filter.put("nickname", newMember.getNickname());
		filter.put("tel", newMember.getTel());

		// 회원 가입
		memberDao.insertMember(filter);
		
		System.out.println("<< 회원 가입 성공 >>");
	}
}

방법5. DTO

 

1. Member1.xml 쿼리 파일을 복사하고 파일명을 Membe5.xml 로 지정하자

<?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="com.study.chapter04.MemberDao5">
	<insert id="insertMember">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{id}, #{pw}, #{nickname}, #{tel});
	</insert>

	<select id="selectMember" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{nickname};
	</select>
</mapper>

 

2. MemberDao1 DAO를 복사하고 인터페이스명을 Member5 로 지정하자

package com.study.chapter04;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface MemberDao5 {
	void insertMember(InsertMemberDto newMemberDto);
	SelectMemberDto selectMember(SelectMemberDto memberDto);
}


3. MyBatisController1 컨트롤러를 복사하고 컨트롤러명을 MyBatisController5 로 지정하자

package com.study.chapter04;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;

@Controller
public class MyBatisController5 {
	@Autowired
	private MemberDao5 memberDao;
	
	@GetMapping("/chapter04/mybatis/v5/member")
	public void getMemberByNickname(SelectMemberDto selectMemberDto) {
		System.out.println("<< 닉네임으로 회원 정보 조회 시작 >>");
		
		// 닉네임으로 회원 정보 조회
		SelectMemberDto member = memberDao.selectMember(selectMemberDto);
		
		// 조회한 회원 정보 출력
		System.out.println(member);
		
		System.out.println("<< 닉네임으로 회원 정보 조회 종료 >>");
	}
	
	@PostMapping("/chapter04/mybatis/v5/member")
	public void insertMember(InsertMemberDto newMember) {
		System.out.println("<< 회원 가입 시작 >>");
		
		// 회원 가입
		memberDao.insertMember(newMember);
		
		System.out.println("<< 회원 가입 성공 >>");
	}
}

여기까지 쿼리가 사용할 값으로 다양한 형태의 값을 보내고 사용하는 방법을 알아봤음

 

쿼리가 값을 사용할 때 쿼리를 감싸고 있는 태그에 parameterType을 명시해줘야함

그러나 우리는 parameterType을 명시하지 않았음

parameterType을 명시하지 않으면 MyBatis가 쿼리와 연결될 DAO의 메서드의 매개변수 타입을 보고 알아서 채워넣음

이는 좋지 못함

 

이 글의 마지막으로 상황별 적절한 parameterType을 지정하는 방법을 알아보자

 

방법1. 쿼리에서 #{param1}, #{param2}, #{param3} ... 처럼 #{param숫자} 로 값을 사용할 때는 쿼리를 감싸고 있는 태그에 parameterType을 명시할 수 없음

 

방법2. 쿼리에서 방법2. #{0}, #{1}, #{2} ... 처럼 #{숫자} 로 값을 사용할 때 역시 쿼리를 감싸고 있는 태그에 parameterType을 명시할 수 없음

 

방법3. 쿼리에서 @Param 어노테이션 으로 값을 사용할 때 역시 쿼리를 감싸고 있는 태그에 paramterType을 명시할 수 없음

 

방법1 ~ 방법3까지는 쿼리에서 값을 사용할 때 parameterType을 명시할 수 없음

방법1 ~ 방법3까지는 실제 개발에서 아예 라고 할 수 있을 정도로 거의 사용하지 않는 방법임

우리는 파라미터를 사용하는 방법을 배우고 있기 때문에 쿼리가 단순해서 방법1 ~ 방법3 을 사용해 쿼리를 만든다고 해도 가독성이 떨어지지 않지만 실무에서는 방법1 ~ 방법3 을 사용해 쿼리를 만들면 가독성이 심하게 떨어지기 때문...

 

 

실무에서는 방법4 또는 방법5를 많이 사용하며 특히, 방법5가 일반적임

 

방법4. 쿼리에서 해시맵 으로 값을 사용할 때는 parameterType을 hashmap 으로 명시해야함

Member4.xml 파일에 들어있는 쿼리들이 해시맵을 사용하므로 Member4.xml 내 insert, select 태그를 정확하게 사용하려면 다음과 같이 사용해야함

<mapper namespace="com.study.chapter04.MemberDao4">
	<insert id="insertMember" parameterType="HashMap">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{item1}, #{item2}, #{nickname}, #{tel});
	</insert>

	<select id="selectMember" parameterType="hashmap" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{key};
	</select>
</mapper>

프로그래밍은 대소문자를 엄격히 구분하기 때문에 parameterType을 쓸 때 hashmap 은 대소문자를 정확히 맞춰 입력해야함

 

 

방법5. 쿼리에서 DTO 로 값을 사용할 때는 parameterType을 DTO의 전체 경로인 패키지명.클래스명 으로 명시해야함

Member5.xml 파일에 들어있는 쿼리들이 DTO를 사용하므로 Member5.xml 내 insert, select 태그를 정확하게 사용하려면 다음과 같이 사용해야함

<?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="com.study.chapter04.MemberDao5">
	<insert id="insertMember" parameterType="com.study.chapter04.InsertMemberDto">
		INSERT INTO member(id, pw, nickname, tel) VALUES(#{id}, #{pw}, #{nickname}, #{tel});
	</insert>

	<select id="selectMember" parameterType="com.study.chapter04.SelectMemberDto" resultType="com.study.chapter04.SelectMemberDto">
		SELECT * FROM member WHERE nickname = #{nickname};
	</select>
</mapper>

 

이외에도 쿼리에서 다양한 타입의 값을 사용할 수 있음

쿼리에 사용할 수 있는 타입명은 아래 표를 참고하자

데이터 타입명
쿼리에서 사용할 값이 [ boolean ] 이라면 paramterType은 [ _boolean ] 으로 명시
쿼리에서 사용할 값이 [ byte ] 라면 paramterType[ _byte ] 명시
쿼리에서 사용할 값이 [ short ] 이라면 paramterType[ _short ]  명시
쿼리에서 사용할 값이 [ int ] 라면 paramterType [ _int ]  명시
쿼리에서 사용할 값이 [ long ] 이라면 paramterType [ _long ] 으로 명시
쿼리에서 사용할 값이 [ float ] 이라면 paramterType [ _float ] 으로 명시
쿼리에서 사용할 값이 [ double ] 이라면 paramterType [ _double ] 으로 명시
쿼리에서 사용할 값이 [ Boolean ] 이라면 paramterType [ boolean ] 으로 명시
쿼리에서 사용할 값이 [ Byte ] 라면 paramterType [ byte ]  명시
쿼리에서 사용할 값이 [ Short ] 이라면 paramterType [ short ]  명시
쿼리에서 사용할 값이 [ Integer ] 라면 paramterType [ int ]  명시
쿼리에서 사용할 값이 [ Long ] 이라면 paramterType [ long ] 으로 명시
쿼리에서 사용할 값이 [ Float ] 이라면 paramterType [ float ] 으로 명시
쿼리에서 사용할 값이 [ Double ] 이라면 paramterType [ double ] 으로 명시
쿼리에서 사용할 값이 [ Object ] 라면 paramterType [ object]  명시
쿼리에서 사용할 값이 [ String ] 이라면 paramterType [ string ] 으로 명시
쿼리에서 사용할 값이 [ Date ] 라면 paramterType [ date ]  명시
쿼리에서 사용할 값이 [ Map ] 이라면 paramterType [ map ] 으로 명시
쿼리에서 사용할 값이 [ HashMap ] 이라면 paramterType [ hashmap ] 으로 명시
쿼리에서 사용할 값이 [ List ] 라면 paramterType [ list ]  명시
쿼리에서 사용할 값이 [ ArrayList ] 라면 paramterType [ arraylist ]  명시
쿼리에서 사용할 값이 [ Collection ] 이라면 paramterType [ collection ] 으로 명시
쿼리에서 사용할 값이 [ Iterator ] 라면 paramterType [ iterator ]  명시
쿼리에서 사용할 값이 [ ResultSet ] 이라면 paramterType [ ResultSet ] 으 명시

이 표는 외울 필요는 없음

그리고 어떻게 활용하는지에 대해서는 곧 배우게 될 것

728x90
LIST