![]() | ![]() |
---|
MyBatis는 자바의 영속성 프레임워크로 자바 어플리케이션에서 JDBC를 통한 데이터베이스로의 접근 및 쿼리 수행을 간소화하고 SQL 쿼리와 프로그램 코드를 분리하여 가독성 및 유지보수의 이점을 가지고 있다.
※ 영속성이란 : 데이터를 생성, 사용후에도 지속성을 보장하는것. 데이터의 안정성과 일관성을 보장한다.
- 객체와 SQL 사이의 여러가지 Mapping 방법을 지원하여 유지보수 및 사용성이 편하다.
- SQL문과 프로그래밍 코드 분리 가능하다.
- 다양한 프로그래밍 언어 사용 가능하다.
- 동적 쿼리와 다양한 파라미터의 바인딩이 가능하다.
- 커밋, 롤백등 트랜잭션 관리가 가능하다.
- 다양한 DB 지원
- 자체적으로 chache를 지원하고 범위 지정 및 온오프를 할 수 있다.
※ 프로젝트 환경 : SpringBoot 2.7.12, OracleDB, Window, IntelliJ, Gradle
1. Dependency 추가
1-1 Gradle의 경우 / build.gradle
implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.3.0' runtimeOnly 'com.oracle.database.jdbc:ojdbc8'
1-2 Maven의 경우 / pom.xml
<dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc8</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.3.0</version> </dependency>
2. application.properties 설정 추가
2-1 DB 설정
DB와의 연결을 위한 url 및 유저 정보를 설정 한다. Oracle을 기준으로 작성된 APITEST 계정의 설정 사항2-2 mapper 파일에 대한 경로 지정
#mapper에 대한 경로를 resources/mybatis/mappers/ 의 모든 xml파일로 지정한다. mybatis.mapper-locations=mybatis/mappers/*.xml
2-3 사용할 수 있는 주요 옵션
# MyBatis의 설정 파일(XML)의 경로를 지정한다. 설정한 classpath 하위에 config 파일을 가르킨다. mybatis.config-location=classpath:mybatis-config.xml ㅤ # 카멜 케이스와 스네이크 케이스의 대한 mapping을 자동 설정한다. mybatis.configuration.map-underscore-to-camel-case=true ㅤ # 선택한 패키지 하위 클래스에 별칭을 정한다. com.apiTest 패키지 하위 클래스를 모두 클래스명으로한 별칭으로 정한다. mybatis.type-aliases-package=com.apiTest.firstTest ㅤ # 캐시 사용 여부 설정 mybatis.configuration.cache-enabled=false
링크에서 설정에 대한 다른 정보 확인 할 수 있다.
3. Mapper.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="TestMapper"> <select id="testSelect" resultType="Test"> SELECT * FROM TEST </select> <update id="testUpdate"> UPDATE TEST SET USER_NAME=#{userName} WHERE USER_NO=#{userNo} </update> <insert id="testInsert"> INSERT INTO TEST VALUES(#{userNo},#{userName}) </insert> <delete id="testDelete"> DELETE FROM TEST WHERE USER_NO = #{userNo} </delete> </mapper>
DB를 바탕으로 Mapper.xml을 작성한다. 보기와 같이 SELECT, UPDATE, INSERT, DELETE를 쿼리로 작성하여 수행한다.
<mapper namespace="mapper에서 사용될 이름">
먼저 mapper로 사용될 이름을 지정한다.
<select id="testSelect" resultType="Test"> SELECT * FROM TEST </select> <update id="testUpdate"> UPDATE TEST SET USER_NAME=#{userName} WHERE USER_NO=#{userNo} </update> <insert id="testInsert"> INSERT INTO TEST VALUES(#{userNo},#{userName}) </insert> <delete id="testDelete"> DELETE FROM TEST WHERE USER_NO = #{userNo} </delete>
mapper 태그 내부에 사용할 쿼리에 대한 엘리먼트를 작성하고 그에 맞는 쿼리를 작성한다.
SELECT 같은 경우 resultType 또는 resultMap과 같은 결과값 타입을 지정해야 한다.
이때 WHERE절에 사용될 파라미터에 #{변수명}을 사용하여 동적 바인딩으로 쿼리를 수행 할 수 있다.4. 테스트
4-1 DB 테스트 테이블 생성 및 테스트 값 세팅
CREATE TABLE TEST( USER_NO NUMBER PRIMARY KEY, USER_NAME VARCHAR2(10) NOT NULL ); INSERT INTO TEST VALUES(1,'A'); INSERT INTO TEST VALUES(2,'B'); INSERT INTO TEST VALUES(3,'C'); INSERT INTO TEST VALUES(4,'D'); INSERT INTO TEST VALUES(5,'E'); COMMIT;
4-2 환경 설정
mapper.xml에 대한 경로를 지정한다. 프로퍼티의 카멜 케이스와 쿼리의 스네이크 케이스를 자동으로 mapping 한다. com.apiTest 패키지의 하위 클래스들을 클래스명으로 별칭한다.
4-3 테스트 작성
Controller class
@Controller public class TestController { private final TestService testService; ㅤ public TestController(TestService testService) { this.testService = testService; } ㅤ @GetMapping("/selectTest") public void test(){ List<Test> tests = testService.mybatisTest(); for(Test test : tests){ System.out.println(test.toString()); } } }
Service interface 및 class
public interface TestService { List<Test> mybatisTest(); } ----------------------------------------------------------------- @Service public class TestServiceLogic implements TestService{ private final TestRepository testRepository; ㅤ public TestServiceLogic(TestRepository testRepository) { this.testRepository = testRepository; } ㅤ @Override public List<Test> mybatisTest() { return testRepository.mybatisTest(); } }
Repository interface 및 class
public interface TestRepository { List<Test> mybatisTest(); } ----------------------------------------------------------------- @Repository public class TestRepositoryLogic implements TestRepository{ private final SqlSession session; ㅤ public TestRepositoryLogic(SqlSession session) { this.session = session; } ㅤ @Override public List<Test> mybatisTest() { return session.selectList("TestMapper.testSelect"); } }
DTO
public class Test { private int userNo; private String userName; ...getter, setter }
해당 코드는 Controller에서 Get 요청으로 "/selectTest"를 받게 되면 testService의 mybatisTest()를 거쳐 testRepository의 session.selectList("TestMapper.testSelect")를 실행하게 된다.sesson : sql 사용을 위한 선언 selectList() : select를 수행, 쿼리 수행 후 결과값이 여러개, 리턴값은 List<obj>이다. "TestMapper.testSelect" : Mapper의 nameSpace 지정.해당 Mapper 내부 엘리먼트를 지정한다.
작업이 실행된 후 결과는 콘솔에 System.out.println(test.toString()) 를 통해 테스트 통과를 확인할 수 있다.
프로퍼티(카멜 케이스)와 컬럼명(스네이크 케이스)으로 Mapping 하는 방법
프로퍼티(카멜 케이스) ![]() | 테이블(스네이크 케이스)![]() | 결과![]() |
---|
mybatis.configuration.map-underscore-to-camel-case=true -------------------------------------------------------- <select id="testSelect" resultType="Test"> SELECT * FROM TEST </select>
application.properties에 위 설정을 추가후 아래 쿼리를 실행한 결과 자동으로 프로퍼티와 컬럼이 Mapping되어 결과값이 정상적으로 출력되는 모습을 확인 할 수 있다.
※ 카멜 케이스 : camelCase. 첫번째 단어는 소문자로 시작하고, 두번째 단어는 대문자로 시작한다. ※ 스네이크 케이스 : snake_case. 첫번째 단어와 두번째 단어 사이에 언더바를 사용한다.
XML파일에 resultMap 요소를 적용하여 컬럼명과 프로퍼티의 이름이 다른경우에도 Mapping이 가능하다.
프로퍼티 ![]() | 테이블![]() | 결과 ![]() |
---|
<resultMap id="testMap" type="Test"> <id column="no" property="userNo" jdbcType="INTEGER" javaType="int"/> <result column="name" property="userName" jdbcType="VARCHAR" javaType="String"/> </resultMap> <select id="test" resultMap="testMap"> SELECT * FROM API_TABLE </select>
자바 프로퍼티명과 Table의 컬럼명이 다름에도 resultMap을 사용하여 결과값이 자동으로 Mapping된 것을 확인 할 수 있다.
id는 테이블의 pk값을 의미하며 result는 컬럼을 의미한다. column : 컬럼명 property : 프로퍼티명 jdbcType,javaType : java와 sql의 데이터 타입이 다르기 때문에 설정을 통해 mapping 해준다.
※ jdbc, javaType 에 대한 mapping 목록 : 링크
MyBatis는 자체적으로 cache를 지원한다. cache에 조회된 결과를 임시로 저장하고 동일한 요청이 있을시 다시 DB에서 조회하는것이 아닌 저장된 결과값을 재사용 함으로써 DB성능 향상에 큰 도움을 줄 수 있다.
- 만약 cache의 데이터와 DB의 데이터가 불일치할 경우
- Insert, Update, Delete와 같은 작업이 있을 경우 저장된 cache와 DB가 불일치 할 수 있다. 이런 경우를 위해 해당 작업이 수행될 경우 자동으로 cache를 비우거나 일정시간 간격으로 비우게 된다.
※ MyBatis에서 cache는 Mapper 단위로 생성되기 때문에 Table 별로 Mapper를 생성하는것이 바람직 하다.- 조회결과는 최대 1024개까지 저장된다.
- cache가 꽉찰경우 오래된 순으로 먼저 지워진다.