본문 바로가기
MyBatis

[MyBatis] select (1) 한 행 조회

by moca7 2024. 10. 11.

 

 

 

ㅁ main.jsp

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

    <h3>1. insert연습 (공지사항 등록)</h3>
    <a href="${ contextPath }/regist.no">공지사항 등록페이지로 이동</a>
 

    <h3>2. select연습 - 한 행 (공지사항 상세조회)</h3>
 
    <form action="${ contextPath }/detail.no">
        검색할 글번호 : <input type="text" name="noticeNo">
        <button type="submit">검색</button>
    </form>

   
    <h3>3. select연습 - 여러행 (공지사항 전체목록조회)</h3>
   
    <h4>4. select연습 - 여러행 + 페이징 처리 - RowBounds 적용</h4>

    <h5>5. select연습 + update연습 (회원정보 상세조회 + 회원정보 변경) - TypeHandler 적용</h5>
   
    <h6>6. 동적쿼리 연습 (회원 검색)</h6>

</body>
</html>
 

 

 

- 공지사항 상세조회는 한 행만 조회된다.

- 보통 한 행 조회면 vo 객체로 바로 조회시킨다.

 

 

 

 

 

 

ㅁ com.br.mybatis.notice.controller에 NoticeDetailController 서블릿을 만든다.

 

 
package com.br.mybatis.notice.controller;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.br.mybatis.notice.dto.NoticeDto;
import com.br.mybatis.notice.service.NoticeServiceImpl;

/**
 * Servlet implementation class NoticeDetailController
 */
@WebServlet("/detail.no")
public class NoticeDetailController extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    /**
     * @see HttpServlet#HttpServlet()
     */
    public NoticeDetailController() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        int noticeNo = Integer.parseInt(request.getParameter("noticeNo"));
       
        NoticeDto n = new NoticeServiceImpl().selectNotice(noticeNo);
       
        request.setAttribute("n", n);
        request.getRequestDispatcher("/WEB-INF/views/notice/noticeDetail.jsp").forward(request, response);
       
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

}
 

 

 

- 글번호를 요청시 입력받아서, 글번호로 해당하는 공지사항 게시글 하나를 보여준다.

 

 

 

 

 

ㅁ com.br.mybatis.notice.service의 NoticeServiceImpl에 selectNotice 메소드를 만든다.

 

 
package com.br.mybatis.notice.service;

import static com.br.mybatis.common.template.Template.getSqlSession;

import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.br.mybatis.common.dto.PageInfoDto;
import com.br.mybatis.notice.dao.NoticeDao;
import com.br.mybatis.notice.dto.NoticeDto;

public class NoticeServiceImpl implements NoticeService {
   
   
    private NoticeDao noticeDao = new NoticeDao();
   


    @Override
    public int insertNotice(NoticeDto n) {
       
        SqlSession sqlSession = /*Template.*/getSqlSession();
       
        int result = noticeDao.insertNotice(sqlSession, n);
 
       
        if(result > 0) {
            sqlSession.commit();
        }
       
        sqlSession.close();
       
        return result;
    }

   
   
    @Override
    public NoticeDto selectNotice(int noticeNo) {
       
        SqlSession sqlSession = getSqlSession();
        NoticeDto n = noticeDao.selectNotice(sqlSession, noticeNo);
       
        sqlSession.close();
        return n;
    }

   
    @Override
    public List<NoticeDto> selectList() {
        return null;
    }

   
    @Override
    public int selectListCount() {
        return 0;
    }

   
    @Override
    public List<NoticeDto> selectList(PageInfoDto pi) {
        return null;
    }
   

}
 

 

 

- MyBatis의 SqlSession 객체는 JDBC의 Connection 객체와 유사한 역할을 한다. 

- MyBatis는 SqlSession을 통해 데이터베이스와의 통신을 관리하고, SQL 쿼리를 실행하며 트랜잭션을 처리한다.

 

 

 

 

 

ㅁ com.br.mybatis.notice.dao의 NoticeDao에 selectNotice 메소드를 만든다.

 

 

 
package com.br.mybatis.notice.dao;

import org.apache.ibatis.session.SqlSession;

import com.br.mybatis.notice.dto.NoticeDto;

public class NoticeDao {

    public int insertNotice(SqlSession sqlSession, NoticeDto n) {
       
        return sqlSession.insert("noticeMapper.insertNotice", n);
    }
   
    public int updateNotice(SqlSession sqlSession, NoticeDto n) {
       
        return sqlSession.update("noticeMapper.updateNotice", n);
       
    }
   
    public int deleteNotice(SqlSession sqlSession, int noticeNo) {
       
        return sqlSession.delete("noticeMapper.deleteNotice", noticeNo);
    }

    public NoticeDto selectNotice(SqlSession sqlSession, int noticeNo) {
       
        return sqlSession.selectOne("noticeMapper.selectNotice", noticeNo);
    }

}
 

 

 

 

 

 


- 조회결과가 한 행일 때는 selectOne 메소드, 조회결과가 여러행일 때는 selectList 메소드를 사용한다.

 

- select 메소드들의 반환형이 T다. 쿼리문의 resultType에 적은 type으로 반환된다.

 

 

 

 

 

 

ㅁ notice-mapper.xml에 "selectNotice" 쿼리를 추가한다.

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="noticeMapper">

    <insert id="insertNotice" parameterType="com.br.mybatis.notice.dto.NoticeDto">
        insert
          into notice
          (
            notice_no
          , notice_title
          , notice_content
          , notice_writer
          )
          values
          (
            seq_nno.nextval
          , #{ noticeTitle }
          , #{ noticeContent }
          , #{ noticeWriter }
          )      
    </insert>

    <update id="updateNotice" parameterType="com.br.mybatis.notice.dto.NoticeDto">
        update
                notice
           set
                notice_title = #{ noticeTitle }
              , notice_content = #{ noticeContent }
         where
                notice_no = #{ noticeNo }              
    </update>

    <delete id="deleteNotice" parameterType="_int">
        delete
          from notice
         where notice_no = #{ noticeNo }
    </delete>


    <!-- (1) 별칭을 사용하는 방법
 
    <select id="selectNotice" resultType="NoticeDto">
        select
                notice_no as "noticeNo"
              , notice_title as "noticeTitle"
              , notice_content as "noticeContent"
              , user_id as "noticeWriter"
              , to_char(regist_date, 'YY/MM/DD HH:MI') as "registDate"
          from notice n
          join member on (notice_writer=user_no)
         where n.status = 'Y'
           and notice_no = #{ noticeNo }        
    </select>
 
    -->
 

     <!-- (2) 별칭을 사용하지 않는 방법 -->
    <resultMap id="noticeResultMap" type="NoticeDto">
        <result column="notice_no" property="noticeNo" />
        <result column="notice_title" property="noticeTitle" />
        <result column="notice_content" property="noticeContent" />
        <result column="user_id" property="noticeWriter" />
        <result column="regist_date" property="registDate" />
    </resultMap>


    <select id="selectNotice" resultMap="noticeResultMap">
        select
                notice_no
              , notice_title
              , notice_content
              , user_id
              , to_char(regist_date, 'YY/MM/DD HH:MI') as "regist_date"
          from notice n
          join member on (notice_writer=user_no)
         where n.status = 'Y'
           and notice_no = #{ noticeNo }        
    </select>

</mapper>
 

 

 

- (1) 별칭을 사용하는 방법, (2) 별칭을 사용하지 않는 방법 전부 한번에 작성한 상태다.

 

- DB의 regist_date 컬럼은 DATE형이다.

NoticeDto 객체의 registDate 컬럼은 이번에 String으로 선언했었다.

DB에서 조회할 때 "to_char 함수"를 통해서 날짜값을 "문자열"로 받는다. 

 

- 이전엔 조회 결과를 rset으로 받고 rset에서 하나씩 컬럼값을 뽑아서 우리가 원하는 dto 객체의 각 필드에 담았었다.

그럴 필요 없이, resultType인 NoticeDto 객체가 생성되어 필드에 조회된 값이 담겨서 반환된다.

 

 

 

====================================================================

 

 

 

※ select 태그

- select 태그는 resultType 또는 resultMap을 반드시 써야 한다.

- select는 결과에 대한 타입을 뭐로 반환할지 반드시 써야 한다.

 

(1) resultType 사용 - 조회 결과를 담아서 반환하고자 하는 객체 타입을 바로 제시하는 경우

(2) resultMap사용 - 매핑시키는 내용을 따로 정의해두는 경우

 

 

 

 

 

(1) resultType 사용 - 조회 결과를 담아서 반환하고자 하는 객체 타입을 바로 제시하는 경우

 

 

 

 

- 쿼리 실행 후

notice_no는 NoticeDto 객체의 noticeNo에,

notice_title은 NoticeDto 객체의  noticeTitle에,

notice_content는 NoticeDto 객체의 noticeContent에,

user_id는 NoticeDto 객체의 noticeWriter에,

to_char()는 NoticeDto 객체의 registDate에 담는다.

 

- 이때 db에서 조회되는 컬럼명이 담고자하는 객체의 필드명과 일치해야 한다.

일치하지 않으면 위와 같이 별칭을 사용해서 "필드명"으로 조회되도록 하면 된다.

 

 

 

 

 

 

※ resultType에 별칭 쓰기( mybatis-config.xml 파일 )

 

- type을 쓰는 곳엔 항상 풀클래스명 아니면 별칭이 들어간다.

- 별칭을 사용하고 싶다면 resources/config/mybatis-config.xml의 typeAliases 태그에 작성하면 된다.

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
  PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 
<configuration>

    <settings>
        <setting name="jdbcTypeForNull" value="NULL" />
    </settings>

   
    <typeAliases>
        <typeAlias type="com.br.mybatis.notice.dto.NoticeDto" alias="NoticeDto" />
    </typeAliases>
   

    <environments default="development">
   
        <environment id="development">
            <transactionManager type="JDBC" />
            <dataSource type="POOLED">
                <property name="driver" value="oracle.jdbc.driver.OracleDriver" />
                <property name="url" value="jdbc:oracle:thin:@localhost:1521:xe" />
                <property name="username" value="SERVER" />
                <property name="password" value="SERVER" />
            </dataSource>
        </environment>
       
    </environments>

   
    <mappers>
        <mapper resource="mappers/notice-mapper.xml" />
        <mapper resource="mappers/member-mapper.xml" />
    </mappers>



</configuration>  
 

 

 

- 별칭은 마음대로 정해도 되지만 보통 클래스명으로 쓴다.

 

 

 

 

 

 

ㅁ WEB-INF/views/notice/noticeDetail.jsp 만든다

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<c:set var="contextPath" value="${pageContext.request.contextPath}" />

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>


    <h3>공지사항 상세조회</h3>

    <c:choose>
        <c:when test="${ empty n }">
            검색된 공지사항이 없습니다.
        </c:when>
       
        <c:otherwise>
            글번호 : ${ n.noticeNo } <br>
            글제목 : ${ n.noticeTitle } <br>
            글내용 : ${ n.noticeContent } <br>
            작성자 : ${ n.noticeWriter } <br>
            작성일 : ${ n.registDate } <br>
        </c:otherwise>
    </c:choose>

</body>
</html>
 

 

 

 

 

 

ㅁ 한 행 조회 해보기

 

 

 

 

 

 

 

 

 

 

 

====================================================================

 

 

 

 

(2) resultMap사용 - 매핑시키는 내용을 따로 정의해두는 경우

 

- resultMap을 사용하면 db의 컬럼명과 dto 객체의 필드명을 일치시키기 위해 쿼리문의 헤드부에 별칭을 쓰지 않아도 된다.

 

- ResultSet으로부터 조회된 컬럼값을 내가 지정한 dto객체의 필드에 매핑시켜주는 코드가 내부적으로 수행된다.

 

 

<resultMap id="식별자" type="조회결과를 담아서 반환하고자하는 dto 객체의 타입(풀클래스명 or 별칭)">

    <result column="컬럼명" property="필드명" />

    <result column="컬럼명" property="필드명" />

    <result column="컬럼명" property="필드명" />

<resultMap> 

 

 

- column 속성에 작성하는 컬럼명은 대소문자를 가리지 않음. db의 컬럼명이다.

- property에 작성되는 필드명은 대소문자를 가린다. dto 객체의 필드명만 써야 한다.

 

 

 

 

- column 속성값의 "컬럼명"으로 조회된 값이 "있으면" 뽑아서 (없다고 문제되진 않음)

property 속성값의 "필드명"의 필드에 mapping하고(담고)

type 속성값의 "dto 객체"로 반환하는 resultMap을 정의한다.

 

 

- select문에 resultMap 속성을 사용해서 해당 resultMap을 참조시키고,

resultMap의 type의 dto 객체로 반환한다.

 

 

 

 

 

 

 

 

ㅁ /mybatisProject/resources/mappers의 notice-mapper.xml에 수정한다.

 

 
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
<mapper namespace="noticeMapper">

    <insert id="insertNotice" parameterType="com.br.mybatis.notice.dto.NoticeDto">
        insert
          into notice
          (
            notice_no
          , notice_title
          , notice_content
          , notice_writer
          )
          values
          (
            seq_nno.nextval
          , #{ noticeTitle }
          , #{ noticeContent }
          , #{ noticeWriter }
          )      
    </insert>

    <update id="updateNotice" parameterType="com.br.mybatis.notice.dto.NoticeDto">
        update
                notice
           set
                notice_title = #{ noticeTitle }
              , notice_content = #{ noticeContent }
         where
                notice_no = #{ noticeNo }              
    </update>

    <delete id="deleteNotice" parameterType="_int">
        delete
          from notice
         where notice_no = #{ noticeNo }
    </delete>


    <!-- (1) 별칭을 사용하는 방법
    <select id="selectNotice" resultType="NoticeDto">
        select
                notice_no as "noticeNo"
              , notice_title as "noticeTitle"
              , notice_content as "noticeContent"
              , user_id as "noticeWriter"
              , to_char(regist_date, 'YY/MM/DD HH:MI') as "registDate"
          from notice n
          join member on (notice_writer=user_no)
         where n.status = 'Y'
           and notice_no = #{ noticeNo }        
    </select>
    -->
 

    <!-- (2) 별칭을 사용하지 않는 방법
    <resultMap id="noticeResultMap" type="NoticeDto">
        <result column="notice_no" property="noticeNo" />
        <result column="notice_title" property="noticeTitle" />
        <result column="notice_content" property="noticeContent" />
        <result column="user_id" property="noticeWriter" />
        <result column="regist_date" property="registDate" />
    </resultMap>


    <select id="selectNotice" resultMap="noticeResultMap">
        select
                notice_no
              , notice_title
              , notice_content
              , user_id
              , to_char(regist_date, 'YY/MM/DD HH:MI') as "regist_date"
          from notice n
          join member on (notice_writer=user_no)
         where n.status = 'Y'
           and notice_no = #{ noticeNo }        
    </select>


</mapper>
 

 

 

- select는 무조건 resultType, resultMap 둘 중에 하나만 작성해야 한다.

- select태그에 resultType이 아닌 resultMap 속성을 사용한다.

속성값으로 어떤 id의 resultMap을 참조시킬지 작성한다.

 

 

- 함수식은 길어서 별칭을 부여했다. 

 

 

- resultType 보다 resultMap을 쓰는게 더 권장된다. 

왜냐면 공지사항에 대해 조회할 때 마다 일일이 쿼리문에 별칭을 부여할 바에는

아예 resultMap을 하나 정의해두고 매번 select 태그에서 참조하게 해서 재사용이 하는 것이 좋다.

 

 

- resultType, resultMap 속성은 select 태그에서만 사용한다.

insert, update, delete 태그들은 반환값의 타입을 명시하지 않아도 되기 대문에 사용하지 않는다.