프로젝트와 데이터베이스를 연결하고자 하는 개발자들이라면 떠오르는 프레임워크가 2개 있을 것이다.
그것은 바로 MyBatis와 JPA일 것이라 생각한다.
이번 포스팅은 많은 기업들이 사용하고 있는 SQL Mapper, MyBatis의 이론 및 초기 설정에 대해 작성하려 한다.
1. MyBatis란 무엇일까
MyBatis는 널리 사용되고 있는 대표적인 SQL Mapper 프레임워크다.
Spring Framework와 함께 사용되는 경우가 많고,
아래와 같은 특징으로 인해 많은 개발자들의 선택을 받고 있다.
1. JDBC를 추상화(Encapsulation)하여 개발자가 프로젝트 內에서 SQL 쿼리를 작성 및 관리하기 쉽도록 해준다.
2. 응답 결과를 Java 객체로 매핑할 수 있도록 하여, 데이터 처리의 복잡도를 낮춘다.
3. SQL 쿼리문을 별도의 XML 파일에 작성하도록 하여 쿼리문 분리가 용이하다.
💡 JDBC (Java Database Connectivity)
Java와 DB를 연결해주는 API로, DB 접속(Connection) 및 SQL문 실행(Statement) 및 SQL 요청 응답 핸들링(ResultSet) 기능을 제공한다.
2. MyBatis를 사용할지, JPA를 사용할지
데이터베이스 매핑에 자주 쓰이는 양대산맥,
MyBatis와 JPA 중 무엇을 사용해야할지 고민일 것이다.
그렇다면 둘의 차이에 대해 알아보도록 하자.
1. SQL Mapper와 ORM
MyBatis는 SQL Mapper 기술로, 개발자가 직접 SQL 쿼리문을 작성하고 매개변수 및 반환 객체를 직접 매핑해줄 수 있다.
반면, JPA는 ORM 기술로, 개발자가 객체 모델을 정의하면 JPA가 객체와 DB 테이블을 자동으로 매핑해준다.
2. 쿼리문 성능 및 개발 생산성
JPA는 추상화 수준이 높기 때문에 단순한 쿼리의 자동 생성으로 개발 생산성을 높일 수 있으나,
복잡한 쿼리가 필요하다면, 성능 면에서는 당연히 쿼리 최적화가 가능한 MyBatis가 유리하다고 볼 수 있다.
즉, 이를 요약하자면 프로젝트의 요구사항에 따라
간단한 CRUD만 필요할 경우 개발 생산성이 좋은 JPA를,
복잡한 쿼리문의 성능 최적화가 필요하다면 직접 SQL 쿼리문을 작성할 수 있는 MyBatis를 사용하는 것이 바람직하다.
3. 초기 설정 코드
MyBatis에 대해 이해가 되었고 MyBatis를 사용하기로 결심했다면,
직접 Spring Boot에서 MyBatis를 적용하는 초기 설정 코드를 작성하며 실습을 해보도록 하자.
샘플 코드를 참고하여 자신의 프로젝트에 맞게 적용하면 된다.
build.gradle
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:3.0.3' #MyBatis dependency
runtimeOnly 'org.mariadb.jdbc:mariadb-java-client' #매핑할 DBMS dependency
먼저 MyBatis 적용에 필요한 의존성을 먼저 설치해주어야 한다.
우리에게 필요한 것은 사용할 DBMS의 의존성 및 MyBatis 의존성이다.
예시는 MariaDB 기준으로 작성되었는데, 자신이 사용하는 DBMS 의존성을 어떻게 작성해야하는지 모르겠다면
Maven Repository 웹페이지에서 검색해보면 Maven과 Gradle에서의 의존성 작성법을 모두 찾을 수 있다.
application.properties
# DB Connection
spring.datasource.driver-class-name=org.mariadb.jdbc.Driver
spring.datasource.url=jdbc:mariadb://{DB URL}:{DB Port}/{Schema}?serverTimezone=UTC&autoReconnect=true&allowMultiQueries=true&characterEncoding=UTF-8
spring.datasource.username={DB Username}
spring.datasource.password={DB Password}
# MyBatis Mapping
spring.web.resources.add-mappings=true
mybatis.config-location=classpath:mybatis/config/myBatisConfig.xml
mybatis.type-aliases-package=com.sample.academy.model.vo
application.properties에서는 DB Connection 및 MyBatis Mapping과 관련된 설정을 작성해 준다.
spring.datasource.driver-class-name
: 사용할 데이터베이스 드라이버를 정의한다.
Oracle | oracle.jdbc.driver.OracleDriver |
MySQL | com.mysql.cj.jdbc.Driver |
MariaDB | org.mariadb.jdbc.Driver |
SQL Server (MSSQL) | com.microsoft.sqlserver.jdbc.SQLServerDriver |
PostgreSQL | org.postgresql.Driver |
spring.datasource.url
: 사용할 데이터베이스의 URL을 정의한다.spring.datasource.username
: 사용할 데이터베이스의 사용자 이름을 정의한다.spring.datasource.password
: 사용할 데이터베이스의 비밀번호를 정의한다.
spring.web.resources.add-mappings
: 웹 리소스 매핑을 활성화 한다. src/main/resources와 하위 레포지토리들의 Path가 /가 된다. Default가 True기 때문에 굳이 명시해주지 않아도 된다.mybatis.config-location
: MyBatis Configuration 파일의 경로를 정의한다.mybatis.type-aliases-package
: MyBatis에서 사용할 Mapping 타입의 별칭 패키지를 미리 정의해둔다. 해당 레포지토리 하위에 있는 파일은 Mapper 파일에서 별도로 경로를 정의할 필요가 없다.
🎨 DB 연결 성능을 향상시키기 위한 Hicari CP(Connection Pool) 설정
spring.datasource.hikari.data-source-properties.cachePrepStmts=true #PreparedStatement 캐싱 활성화
spring.datasource.hikari.data-source-properties.prepStmtCacheSize=200 #PreparedStatement 캐시 크기
spring.datasource.hikari.data-source-properties.prepStmtCacheSqlLimit=2048 #PreparedStatement 캐시 SQL 문장 크기 제한
spring.datasource.hikari.data-source-properties.useServerPrepStmts=true #서버 PreparedStatement 사용
spring.datasource.hikari.minimumIdle=5 #최소 유휴 연결 수
spring.datasource.hikari.connectionTimeout=10000 #연결 획득 시간 제한 (ms)
spring.datasource.hikari.maximumPoolSize=10 #최대 연결 풀 크기
spring.datasource.hikari.maxLifeTime=580000 #연결 최대 수명 (ms)
spring.datasource.hikari.autoCommit=true #자동 커밋 모드
resources/mybatis/config/myBatisConfig.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 언더바 속성을 CamelCase로 변경 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<mappers>
<mapper resource="mybatis/mappers/student.xml" />
</mappers>
</configuration>
보통 DB는 대소문자를 구분하지 않아 두 단어를 합칠 땐 create_dt
처럼 언더바를 사용한다.
반면 Java 필드를 작성할 땐 대소문자가 구분되기 때문에 createDt
와 같이 카멜 케이스를 사용하는 것이 대다수다.
언더바로 명명된 속성을 카멜 케이스로 작성된 객체의 필드와 매핑될 수 있도록
mapUnderscoreToCamelCase
Setting을 True로 설정해주는 것이다.
각 매핑할 SQL Mapper 파일마다 mapper
태그를 통해 resource
속성으로 연결 시켜준다.
resources/mybatis/mappers/student.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.sample.academy.model.dao.StudentDao">
<insert id="upsert" parameterType="StudentVo">
INSERT INTO STUDENT(`id`, `name`, `age`, `class`)
VALUES (#{id}, #{name}, #{age}, #{class})
ON DUPLICATE KEY UPDATE name = #{name}, age = #{age}, class = #{class};
</insert>
<select id="selectByName" parameterType="String" resultType="StudentVo">
SELECT *
FROM STUDENT
WHERE name LIKE CONCAT('%', #{name}, '%');
</select>
</mapper>
mapper
태그의 namespace
에는 해당 SQL 쿼리문과 매핑할 DAO Interface의 Path를 넣고,
태그 內에 DML 태그를 생성해 SQL 쿼리문을 작성한다.
아래는 DML 태그의 필요 속성들이다.
id
: DAO에서 선언한 메소드명을 정의한다. 해당 메소드를 호출하면 SQL문이 실행된다.parameterType
: 전달인자의 자료형을 정의한다.
전달인자는#{}
,${}
를 이용해 사용할 수 있는데,#{}
는 PreparedStatement방식으로 값을 DB에 전달하여, 보안 면에서 더욱 안전하다.resultType
: 반환된 데이터의 매핑될 자료형을 지정해준다. 반환 튜플이 여러 개라면 한 튜플에 대한 자료형만 기입하면 된다. 예를 들어,List<String>
이 반환되어야 한다면String
만 작성해도 된다는 것.
이외에 더욱 자세한 작성법을 추후 MyBatis 매핑 XML 작성 게시글에서 다루도록 하려 한다.
StudentDao.java
package com.sample.academy.model.dao;
import com.sample.academy.model.vo.BugVo;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
@Repository
public interface StudentDao {
void insert(StudentVo studentVo) throws DataAccessException;
List<StudentVo> selectByName(String name) throws DataAccessException;
}
해당 DAO와 연결된 Mapper 파일에서 작성된 DML 태그의 id를 사용하여 DAO Interface를 만든다.
따로 실행할 Java 코드 없이 SQL 쿼리문을 실행시키고 값을 받아오는 역할만 하기 때문에
선언형 메소드만이 필요하여 Interface 방식으로 작성하는 것이다.
SQL 실행 중 발생하는 Exception을 처리하기 위해 DataAccessException을 서비스에 던져준다.
'프레임워크 및 라이브러리 > Spring' 카테고리의 다른 글
[Spring Boot] MyBatis Bean 주입 오류 available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} (2) | 2024.10.12 |
---|---|
RuntimeException : Cannot invoke "*" because "*" is null 해결 (0) | 2024.07.17 |
[MyBatis] argument type mismatch (0) | 2024.07.01 |
RestClient 자동 인코딩 (공공데이터 API Key Error) (0) | 2024.04.12 |
WebClient를 사용하지 않게 된 이유, 그리고 RestClient (1) | 2024.03.27 |