나를 기록하다
article thumbnail
Published 2024. 4. 9. 08:43
[TIL-54/240408] MyBatis TIL
반응형

1. MyBatis

1.1. 특징

  • SQL 매핑 프레임워크
  • SQL문과 저장 프로시저(Stored Procedure)등의 매핑을 지원하는 퍼시스턴스 프레임워크(persistence framework)
  • JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 처리를 대신해줌
  • Map 인터페이스 그리고 자바 POJO를 설정 데이터베이스와 매핑해서 사용 가능
  • XML과 Annotation 설정을 통해 사용할 수 있음

mybatis 처리 과정

 

1.2. MyBatis 동작 구조

MyBatis는 SQL을 처리하고 Java 객체와 DB간의 매핑을 처리한다.

동작 구조

 

1.3. MyBatis 구성 요소

MyBatis는 SqlSession 인터페이스를 통해 DB와 상호작용 한다.

흐름

  • SqlSessionFactory
    • SqlSession 객체를 생성하는 팩토리 클래스
    • 런타임 도중 CRUD 처리 요청에 따라 SqlSession 객체를 생성
    • openSession() 메소드를 통해 객체를 생성
  • SqlSession
    • SQL 실행이나 트랜잭션 관리를 위한 메소드를 가진 인터페이스
    • SELECT, INSERT, UPDATE, DELETE 구문을 수행하기 위해 사용
    • SqlSession을 반드시 닫도록 한다(try with resources로 사용 권장).

 

1.4. MyBatis - 시작하기

  • mybatis-x.x.x.jar 파일을 프로젝트에 추가
  • maven 프로젝트를 사용한다면 pom.xml에 의존성 추가
<java />
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>Spring_06_MyBatis</groupId> <artifactId>Spring_06_MyBatis</artifactId> <version>0.0.1-SNAPSHOT</version> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.1</version> <configuration> <release>17</release> </configuration> </plugin> </plugins> </build> <dependencies> <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.15</version> </dependency> <!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.0.33</version> </dependency> </dependencies> </project>

 

1.5. MyBatis - 설정하기( XML 설정파일)

  • 설정파일 작성(resource 폴더) - mybatis-config.xml
<java />
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "https://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <typeAlias type="com.ssafy.board.model.dto.Board" alias="Board"/> </typeAliases> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC" /> <property name="username" value="ssafy" /> <property name="password" value="ssafy" /> </dataSource> </environment> </environments> <mappers> <mapper resource="mappers/boardMapper.xml" /> </mappers> </configuration>

 

  • 작성 순서가 중요함
    • configuration
      1. properties
      2. settings
      3. typeAliases
      4. typeHandlers
      5. objectFactory
      6. plugins
      7. environments
        1. environment
        2. transactionManager
        3. dataSource
      8. dataBaseIdProvider
      9. mappers

 

1.5.1. TypeAliases

  • 타입 별칭은 자바 타입에 대한 짧은 이름, XML 설정에서만 사용
  • 클래스 단위 or 패키지 단위로 등록 가능
  • 이름을 지정하지 않으면 소문자로 바뀐 형태의 값이 지정
  • 공통 자바 타입을 위한 여러 내장 타입 별칭이 존재(대소문자 구별 x)
  • 오버로딩된 이름 때문에 원시형 타입은 특별 취급
<java />
<typeAliases> <typeAlias type="com.ssafy.board.model.dto.Board" alias="Board"/> </typeAliases>

 

1.5.2. environments

  • 여러 개의 환경으로 설정할 수 있음(개발, 테스트, 실제 환경, 여러 개의 DBMS 등)
  • DB별로 하나의 SqlSessionFactory 사용
<java />
<environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.cj.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/ssafy_board?serverTimezone=UTC" /> <property name="username" value="ssafy" /> <property name="password" value="ssafy" /> </dataSource> </environment> </environments>

 

1.5.3. mappers

  • 매핑된 SQL 구문 설정파일의 위치 작성
  • class path의 상대경로의 리소스 사용
  • 절대경로의 url 사용
  • mapper 인터페이스 사용
  • 매퍼 패키지 내의 모든 인터페이스를 등록
<java />
<mappers> <mapper resource="mappers/boardMapper.xml" /> </mappers>
  • cache → 해당 네임스페이스를 위한 캐시 설정
  • cache-ref → 다른 네임스페이스의 캐시 설정에 대한 참조
  • resultMap → DB 결과 데이터를 객체에 로드하는 방법을 정의
  • parameterMap → 비권장됨(현재 사용 x)
  • sql → 다른 구문에서 재사용하기 위한 SQL 조각
  • insert → 매핑된 INSERT 구문
  • update  → 매핑된 UPDATE 구문
  • delete → 매핑된 DELETE 구문
  • select → 매핑된 SELECT 구문

 

1.6. 예시 - 게시판 만들기

1.6.1. DAO

<java />
public interface BoardDao { // 전체 게시글을 조회 public abstract List<Board> selectAll(); // ID에 해당하는 게시글 하나 가져오기 public abstract Board selectOne(int id); // 게시글 등록 public void insertBoard(Board board); // 게시글 삭제 public void deleteBoard(int id); // 게시글 수정 public void updateBoard(Board board); // 조회수 증가 public void updateViewCnt(int id); }

1.6.2. DTO

<java />
public class Board { private int id; private String title; private String writer; private String content; private String regDate; private int viewCnt; public Board() { } public Board(String title, String writer, String content) { super(); this.title = title; this.writer = writer; this.content = content; } public Board(int id, String title, String writer, String content, String regDate, int viewCnt) { this.id = id; this.title = title; this.writer = writer; this.content = content; this.regDate = regDate; this.viewCnt = viewCnt; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public String getWriter() { return writer; } public void setWriter(String writer) { this.writer = writer; } public String getContent() { return content; } public void setContent(String content) { this.content = content; } public String getRegDate() { return regDate; } public void setRegDate(String regDate) { this.regDate = regDate; } public int getViewCnt() { return viewCnt; } public void setViewCnt(int viewCnt) { this.viewCnt = viewCnt; } @Override public String toString() { return "Board [id=" + id + ", title=" + title + ", writer=" + writer + ", content=" + content + ", regDate=" + regDate + ", viewCnt=" + viewCnt + "]"; } }

1.6.3. MyAppSqlConfig.xml

<java />
import java.io.IOException; import java.io.InputStream; import org.apache.ibatis.io.Resources; import org.apache.ibatis.session.SqlSessionFactory; import org.apache.ibatis.session.SqlSessionFactoryBuilder; public class MyAppSqlConfig { //공장을 세워서 계속 불러다 쓸 계획 private static SqlSessionFactory factory; static { //공장을 세워야 하는데 설정 파일(자원) 위치 String resource = "config/mybatis-config.xml"; try(InputStream inputStream = Resources.getResourceAsStream(resource)) { factory = new SqlSessionFactoryBuilder().build(inputStream); System.out.println("공장 건설 완료"); } catch (IOException e) { e.printStackTrace(); System.out.println("공장 건설 실패"); } } public static SqlSessionFactory getFactory() { return factory; } }

1.6.4. boardMapper.xml

<java />
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://mybatis.org/dtd/mybatis-3-mapper.dtd"> <!-- 네임스페이스에 DAO 풀패키지명을 작성 --> <mapper namespace="com.ssafy.board.model.dao.BoardDao"> <resultMap type="Board" id="boardMap"> <!-- <result column="id" property="id"/> <result column="writer" property="writer"/> <result column="title" property="title"/> <result column="content" property="content"/> --> <result column="view_cnt" property="viewCnt" /> <result column="reg_date" property="regDate" /> </resultMap> <!-- 전체 게시글 조회 --> <select id="selectAll" resultMap="boardMap"> SELECT id, content, writer, title, view_cnt AS viewCnt, date_format(reg_date, '%Y-%M-%D') AS reg_date FROM board; </select> <!-- 상세 게시글 조회 --> <select id="selectOne" resultMap="boardMap" parameterType="int"> SELECT * FROM board WHERE id = #{id}; </select> <!-- 게시글 등록 --> <insert id="insertBoard" parameterType="Board"> INSERT INTO board (title, writer, content) VALUES (#{title}, #{writer}, #{content}); </insert> <!-- 게시글 삭제 --> <delete id="deleteBoard" parameterType="int"> DELETE FROM board WHERE id = #{id}; </delete> <!-- 조회수 증가 --> <update id="updateViewCnt" parameterType="int"> UPDATE board SET view_cnt = view_cnt + 1 WHERE id = #{id}; </update> <!-- 게시글 수정 --> <!-- 만약 날짜가 수정 날짜였다면 같이 수정해줘야 함 --> <update id="updateBoard" parameterType="Board"> UPDATE board SET title = #{title}, content = #{content}, reg_date = now() WHERE id = #{id}; </update> </mapper>

1.6.5. Test

<java />
package com.ssafy.board.test; import java.util.List; import org.apache.ibatis.session.SqlSession; import com.ssafy.board.config.MyAppSqlConfig; import com.ssafy.board.model.dao.BoardDao; import com.ssafy.board.model.dto.Board; public class Test { public static void main(String[] args) { try (SqlSession session = MyAppSqlConfig.getFactory().openSession(true)) { List<Board> boards = session.selectList("com.ssafy.board.model.dao.BoardDao.selectAll"); for (Board board : boards) { System.out.println(board); } } // try(SqlSession session = MyAppSqlConfig.getFactory().openSession(true)) { // BoardDao dao = session.getMapper(BoardDao.class); // Board board = dao.selectOne(1); // System.out.println(board); // } // try(SqlSession session = MyAppSqlConfig.getFactory().openSession(true)) { // BoardDao dao = session.getMapper(BoardDao.class); // Board board = new Board("test","test_writer","test_content"); // dao.insertBoard(board); // System.out.println(board); // } // try(SqlSession session = MyAppSqlConfig.getFactory().openSession(true)) { // BoardDao dao = session.getMapper(BoardDao.class); // dao.deleteBoard(0); // } try(SqlSession session = MyAppSqlConfig.getFactory().openSession(true)) { BoardDao dao = session.getMapper(BoardDao.class); dao.updateViewCnt(3); Board board = dao.selectOne(3); System.out.println(board); } try(SqlSession session = MyAppSqlConfig.getFactory().openSession(true)) { BoardDao dao = session.getMapper(BoardDao.class); Board board = dao.selectOne(1); board.setContent("update content"); dao.updateBoard(board); System.out.println(board); } } }

 

반응형
profile

나를 기록하다

@prao

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!