TIL
[TIL-54/240408] MyBatis
prao
2024. 4. 9. 08:43
반응형
MyBatis
특징
- SQL 매핑 프레임워크
- SQL문과 저장 프로시저(Stored Procedure)등의 매핑을 지원하는 퍼시스턴스 프레임워크(persistence framework)
- JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 처리를 대신해줌
- Map 인터페이스 그리고 자바 POJO를 설정 데이터베이스와 매핑해서 사용 가능
- XML과 Annotation 설정을 통해 사용할 수 있음
MyBatis 동작 구조
MyBatis는 SQL을 처리하고 Java 객체와 DB간의 매핑을 처리한다.
MyBatis 구성 요소
MyBatis는 SqlSession 인터페이스를 통해 DB와 상호작용 한다.
- SqlSessionFactory
- SqlSession 객체를 생성하는 팩토리 클래스
- 런타임 도중 CRUD 처리 요청에 따라 SqlSession 객체를 생성
- openSession() 메소드를 통해 객체를 생성
- SqlSession
- SQL 실행이나 트랜잭션 관리를 위한 메소드를 가진 인터페이스
- SELECT, INSERT, UPDATE, DELETE 구문을 수행하기 위해 사용
- SqlSession을 반드시 닫도록 한다(try with resources로 사용 권장).
MyBatis - 시작하기
- mybatis-x.x.x.jar 파일을 프로젝트에 추가
- maven 프로젝트를 사용한다면 pom.xml에 의존성 추가
<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>
MyBatis - 설정하기( XML 설정파일)
- 설정파일 작성(resource 폴더) - mybatis-config.xml
<?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
- properties
- settings
- typeAliases
- typeHandlers
- objectFactory
- plugins
- environments
- environment
- transactionManager
- dataSource
- dataBaseIdProvider
- mappers
- configuration
TypeAliases
- 타입 별칭은 자바 타입에 대한 짧은 이름, XML 설정에서만 사용
- 클래스 단위 or 패키지 단위로 등록 가능
- 이름을 지정하지 않으면 소문자로 바뀐 형태의 값이 지정
- 공통 자바 타입을 위한 여러 내장 타입 별칭이 존재(대소문자 구별 x)
- 오버로딩된 이름 때문에 원시형 타입은 특별 취급
<typeAliases>
<typeAlias type="com.ssafy.board.model.dto.Board" alias="Board"/>
</typeAliases>
environments
- 여러 개의 환경으로 설정할 수 있음(개발, 테스트, 실제 환경, 여러 개의 DBMS 등)
- DB별로 하나의 SqlSessionFactory 사용
<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
- 매핑된 SQL 구문 설정파일의 위치 작성
- class path의 상대경로의 리소스 사용
- 절대경로의 url 사용
- mapper 인터페이스 사용
- 매퍼 패키지 내의 모든 인터페이스를 등록
<mappers>
<mapper resource="mappers/boardMapper.xml" />
</mappers>
- cache → 해당 네임스페이스를 위한 캐시 설정
- cache-ref → 다른 네임스페이스의 캐시 설정에 대한 참조
- resultMap → DB 결과 데이터를 객체에 로드하는 방법을 정의
- parameterMap → 비권장됨(현재 사용 x)
- sql → 다른 구문에서 재사용하기 위한 SQL 조각
- insert → 매핑된 INSERT 구문
- update → 매핑된 UPDATE 구문
- delete → 매핑된 DELETE 구문
- select → 매핑된 SELECT 구문
예시 - 게시판 만들기
DAO
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);
}
DTO
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 + "]";
}
}
MyAppSqlConfig.xml
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;
}
}
boardMapper.xml
<?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>
Test
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);
}
}
}
반응형