개발군싹

4) mybatis를 이용한 동적 SQL (if,where,trim) 본문

Mybatis

4) mybatis를 이용한 동적 SQL (if,where,trim)

개발자군싹 2023. 12. 4. 20:11

mybatis의 가장 큰 장점은 동적 SQL처리

➡️ JDBC에서는 동적으로 SQL작업을 하는 것이 매우 힘들었지만 mybatis를 이용하여 보다 편리하고 손쉽게 동적 SQL 작업을 이행할 수 있다.

 

JDBC - DAO에서 DB에 접근하여 SQL 실행하기

public int updateStudentInfo (Connection conn, List<Student> student){
	PreparedStatement pstmt = null;
	int result = 0;

	try{
		pstmt = conn.prepareStatemented(sql.getProperty("updateStudentInfo");
		pstmt.setString(1,student.studentName);
		pstmt.setInt(2,student.studentAge);
		...
		result = pstmt.executeUpdate();
	}catch(SQLException e){
		e.printStackTrace();
	}finally{
		close(pstmt);
	}
}

➡️ JDBC를 이용하여 쿼리작성 자체가 물음표의 갯수와 작성한 SQL문에 물음표에 해당하는 값의 타입과 데이터를 개발자가 직접 작성해주는 단점이 있었다. ( mybatis를 알기전에는 당연히 이런 방식으로 접근해야한다고 생각…😥😥)

 

mybatis를 이용한 DAO

public List<Employee> selectEmployeeAll(SqlSession session){
		return session.selectList("employee.selectEmployeeAll");
	}
	
public List<Employee> searchEmployeeByKeyword(SqlSession session, Map<String,Object> item){
	return session.selectList("employee.searchEmployeeByKeyword",item);
}

➡️ 한눈에 보기에도 너무 간편해지는 코드… 물론 -mapper.xml을 통해 설정 작업을 해줘야 하는 부분도 있지만 코드 자체가 간결해지면서 DB에 접근하기 까지의 과정이 mybatis를 사용하기 이전보다 부담이 적다.

 

<select id="selectEmployeeAll" resultMap="employeeMap">
		SELECT *
		FROM EMPLOYEE
</select>

-mapper.xml파일에 간단히 설정하면 쉽게 DB로부터 원하는 데이터를 가져올 수 있다.

 

그래서 동적 SQL이란?

-mapper.xml파일에서 if, choose, trim, foreach문과 같이 조건문, 반복문 등을 이용하여 원하는 데이터를 원하는 조건에 맞게 sql을 작성할 수 있도록 한다.

 

동적 SQL작성에 필요한 태그 종류 (1. if)

⇒ mybatis는 xml파일 기반으로 프로그램을 다루는데 mybatis가 개발해두고 지정해둔 태그를 이용하여 조건문,반복문 등의 코드 제어가 가능한 태그 종류가 있다.

(if, choose(when,otherwise, trim(where, set), foreach )

 

♠️ if ⇒ 동적 SQL에서 가장 공통적으로 많이 사용되는 것, where절을 제어할 때 사용할 수 있다.

<if>태그

  • 표기 : <if test=”조건식” ></if>
  • test ⇒ parameter로 전달된 값을 연산자 비교하여 조건식을 작성한다.

ex) param은 parameter로 전달된 key:value 형식의 Map 타입 가정

<if test=”type==’emp_id’”> ⇒ java code 해석 : param.get(”type”).equals(”emp_id”);

예제) 사원 데이터 전체 조회 SQL ( in employee-mapper.xml )

<select id="selectEmployeeAll" resultMap="employeeMap">
		SELECT *
		FROM EMPLOYEE
</select>

 

➡️ DB에 등록된 사원을 전체 조회한 결과, 해당 사원 데이터를 타입에 맞는 검색, 성별, 급여(이상/이하)에 따른 조건식에 맞게 데이터 출력하기

 

 

  • jsp 화면에서 emp_id, emp_name, email, phone 타입으로 검색 타입을 전달
  • keyword는 사용자의 입력 값을 전달
<td>
	<select name="type">
		<option value="emp_id">사원번호</option>
		<option value="emp_name">사원이름</option>
		<option value="email">이메일</option>
		<option value="phone">전화번호</option>
	</select>
</td>
<td>
	<input type="text" name="keyword" placeholder="검색어입력"/>
	<input type="submit" value="검색"/>
</td>

 

String type = request.getParameter("type");
String keyword = request.getParameter("keyword");

Map<String,Object> param = new HashMap<>();
param.put("type",type);
param.put("keyword",keyword);

List<Employee> employee = new EmployeeService().searchEmployeeByKeyword(param);

request.setAttribute("employee", employee);
request.getRequestDispatcher("/views/employee/employeeList.jsp").forward(request, response);

⇒ 사용자가 선택한 type과 입력한 keyword에 해당하는 데이터 변수에 저장 후 Map((key:value)을 이용하여 Mapping

 

employee DTO

public class Employee {
//EMP_ID //EMP_NAME //EMP_NO // EMAIL // PHONE 
//DEPT_CODE // JOB_CODE // SAL_LEVEL // SALARY // BONUS // MANAGER_ID
// HIRE_DATE // ENT_DATE // ENT_YN
	private int empId;
	private String empName;
	private String empNo;
	private String email;
	private String phone;
	private String deptCode;
	private String jobCode;
	private String salLevel;
	private int salary;
	private double bonus;
	private int managerId;
	private Date hireDate;
	private Date entDate;
	private String entYN;
	private String gender;
}

mybatis는 앞서 공부했지만 DB의 컬럼명과 객체의 필드명이 다르기 때문에 맵핑 작업을 해줘야 한다.

<resultMap> 태그 이용

 

 

 ♠️ resultMap 복습

  • resultMap 태그에는 id와 type 속성을 설정해줘야 한다.

→ id : resultMap은 select 태그를 이용하여 결과물을 출력시 해당 결과를 저장할 객체의 필드와 DB의 컬럼명을 설정한 resultMap을 찾기 위해 사용 (고유이름)

→ type : type은 매핑할 DTO객체의 경로를 작성 ( mybatis가 java가 가지고 있는 객체 외 개발자가 직접 생성한 객체에 대한 정보를 모르기 때문에 mybatis가 객체를 찾을 수 있도록 돕기 위해 설정 )

  • resultMap 태그의 자식태그 <id>,<result>

→ id태그는 PrimaryKey(PK)에 해당하는 컬럼 및 필드를 설정

→ result는 그 외의 일반 컬럼과 필드를 설정

 

 

조회 검색 SQL 작성

<select id="searchEmployeeByKeyword" parameterType="map" resultMap="employeeMap">
SELECT *
FROM EMPLOYEE
WHERE ${type} LIKE '%'||#{keyword}||'%'
</select>

➡️ JDBC 이용 시 물음표 개수 맞추고, 각 물음표에 해당하는 컬럼 값을 설정하면서 에러도 많이 겪었지만 위 코드와 직관적으로 SQL문 작성이 가능하여 mybatis를 이용하는 개발자 입장에서 편리.

 

 

성별과 급여 html의 radio 태그를 이용하여 조건에 맞는 데이터 조회

<tr>
	<td>성별</td>
	<td>	
		<label><input type="radio" name="gender" value="M"/>남</label>
		<label><input type="radio" name="gender" value="F" />여</label>
	</td>
</tr>
<tr>
	<td>
		급여
	</td>
	<td>
		<input type="number" min="1500000" step="100000" name="salary"/>
		<label><input type="radio" name="salFlag" value="ge"/>이상</label>
		<label><input type="radio" name="salFlag" value="le"/>이하</label>
	</td>
</tr>

 

 

Controller.java

String type = request.getParameter("type");
		String keyword = request.getParameter("keyword");
		String gender = request.getParameter("gender");
		int salary;
		try {
			salary = Integer.parseInt(request.getParameter("salary"));
		}catch(NumberFormatException e) {
			salary=0;
		}
		String salFlag = request.getParameter("salFlag");
		Map<String,Object> param = new HashMap<>();
		/* Map.of("type",type,"keyword",keyword); */
		param.put("type",type);
		param.put("keyword",keyword);
		param.put("gender", gender);
		param.put("salary", salary);
		param.put("salFlag",salFlag);
		List<Employee> employee = new EmployeeService().searchEmployeeByKeyword(param);
		
		request.setAttribute("employee", employee);
		request.getRequestDispatcher("/views/employee/employeeList.jsp").forward(request, response);

타입에 맞는 검색 기능에 ‘gender’ 와 ‘salary’ 데이터를 Map에 저장시켜 전달

⇒ JDBC를 이용하여 코드 작성의 경우 각각의 데이터 조회에 맞는 메소드나 SQL문을 따로 작성해야 하지만 mybatis가 제공하는 동적SQL 을 이용하여 코드 작성


동적 SQL작성에 필요한 태그 종류 (2. where)

♠️ <where></where>태그 내 <if/> 태그를 이용한 조건식에 부합하면 해당 <if> 태그 내 작성한 sql문을 이용할 수 있다. 이때 sql문이 들어나게 되면 where문은 해당 조건식에 ‘WHERE’을 추가해준다.

🔥 해당 sql문이 여러 조건들로 이어진 ‘AND’ || ‘OR’ 논리 연산이 적혀있으면 이를 앞의 조건문이 존재 하지 않을 시 자동으로 지워준다.

SELECT * 
FROM (SELECT E.*, DECODE(SUBSTR(EMP_NO,8,1),'1','M','2','F') AS GENDER
		  FROM EMPLOYEE E)
<where>
	<if test="type!=null and type!='' and keyword != null and keyword != '' ">
		${type} LIKE '%'||#{keyword}||'%'
	</if>
	<if test="gender!=null and gender!='' ">
		AND GENDER = #{gender}
	</if>
</where>

 


동적 SQL작성에 필요한 태그 종류 (3. trim)

  • <trim>태그는 <where>태그와 유사하게 동작한다. 태그의 속성에는 prefix와 prefixOverrides가 있다.

→ prefix ⇒ 조건문이 필요한 경우 ‘WHERE’ UPDATE문 이용시 ‘SET’을 적을 수 있다.( WHERE, SET 을 sql문 앞에 작성해준다. )

→ prefixOverrrides ⇒ “AND | OR” 적을 수 있다. AND와 OR가 필요없이 사용되야 할 경우 AND, OR를 제한하는 역할을 한다.

<trim prefix="WHERE" prefixOverrides="AND|OR">
	<if test="type!=null and type!='' and keyword != null and keyword != '' ">
		${type} LIKE '%'||#{keyword}||'%'
	</if>
	<if test="gender!=null and gender!='' ">
		AND GENDER = #{gender}
	</if>
	<if test="salary!=null and salary>0">
			<if test="salFlag == 'ge'">
				AND SALARY >= #{salary}
			</if>
			<if test="salFlag == 'le'">
				AND SALARY <![CDATA[<=]]> #{salary}
			</if>
	</if>
</trim>