mybatis(마이바티스)

시작하기

의존성 모듈 설정

mybatis-spring-boot-starter mybatis 모듈
mysql:mysql-connector-java mysql 커넥션 모듈

// build.gradle

implementation 'org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.0'
implementation 'mysql:mysql-connector-java'

application.yml

// src/main/resources/application.yml

spring:
    datasource:
        driver-class-name: com.mysql.jdbc.Driver
        jdbc-url: jdbc:mysql://localhost:3306/mysql
        username: root
        password:

mybatis config

classpath:/com/jjamong/mybatis/dao/*.xml mapper 위치

package com.jjamong.mybatis.config;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
@MapperScan(value = "com.jjamong.mybatis.dao", sqlSessionFactoryRef = "SqlSessionFactory")
public class MybatisConfig {

    @Value("classpath:/com/jjamong/mybatis/dao/*.xml")
    String mPath;

    @Bean(name = "dataSource")
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource DataSource() {
        return DataSourceBuilder.create().build();
    }


    @Bean(name = "SqlSessionFactory")
    public SqlSessionFactory SqlSessionFactory(@Qualifier("dataSource") DataSource DataSource, ApplicationContext applicationContext) throws Exception {
        SqlSessionFactoryBean sqlSessionFactoryBean =  new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(DataSource);
        sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mPath));
        return sqlSessionFactoryBean.getObject();
    }

    @Bean(name = "SessionTemplate")
    public SqlSessionTemplate SqlSessionTemplate(@Qualifier("SqlSessionFactory") SqlSessionFactory firstSqlSessionFactory) {
        return new SqlSessionTemplate(firstSqlSessionFactory);
    }

}

controller

package com.jjamong.mybatis.controller;

import java.util.HashMap;
import java.util.List;

import com.jjamong.mybatis.service.IndexService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class IndexController {

    @Autowired
    private IndexService indexService;

    @GetMapping("/")
    public ResponseEntity index() {

        List<HashMap<String, Object>> list = indexService.gets();

        return new ResponseEntity(list, HttpStatus.OK);
    }
}

service

package com.jjamong.mybatis.service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.jjamong.mybatis.dao.IndexMapper;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class IndexService {
    
    @Autowired
    private IndexMapper indexMapper;

    public List<HashMap<String, Object>> gets() {

        List<HashMap<String, Object>> res = new ArrayList<HashMap<String, Object>>();

        res = indexMapper.gets();

        return res;
    } 
}

dao

package com.jjamong.mybatis.dao;

import java.util.HashMap;
import java.util.List;

import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface IndexMapper {
    
    public List<HashMap<String, Object>> gets();
}

mapper

// resources/com/jjamong/mybatis/dao/IndexMapper

<?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.jjamong.mybatis.dao.IndexMapper">

    <select id="gets" resultType="hashMap">
        show databases 
    </select>
</mapper>

이해하기

#과 $의 차이

#{} 방식

성능과 보안적으로 이점이 있어 일반적으로는 #{} 방식을 사용합니다.


#{} 방식은 PreparedStatement를 사용하는데
PreparedStatement는 쿼리가 메모리에 올라가 실행되기 때문에 매번 컴파일 되지 않아(캐싱) 성능이 향상됩니다.

#{} 방식은 매개변수가 ?로 변환되며 보안적으로도 이점이 있고
들어오는 데이터를 문자열로 인식하기 때문에 자동으로 따옴표가 붙습니다.’

보통 일반적으로 #{} 방식을 사용합니다.

PreparedStatement
// PreparedStatement

String sql = "SELECT * FROM USER WHERE id = ?"
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "userId");
ResultSet rst = pstmt.executeQuerey();
사용 예
// 코드
SELECT * FROM USER
WHERE id = #{id}
// 결과
SELECT * FROM USER
WHERE id = ?

${} 방식

매개 변수에 자동 따옴표가 붙지 않아야 하는 곳에서만 사용합니다.


${} 방식은 Statement를 사용하는데,
Statement는 매번 컴파일을 하기 때문에 성능적으로 떯어집니다.

${} 방식은 매개변수를 값 그대로 전달하기 떄문에 보안적(SQL Injection)으로 취약하고 문자열에 자동으로 따옴표가 붙지 않습니다.

문자열을 유동적으로 사용할 수 있어 테이블, 컬럼명, 예약어 사용에 이점이 있습니다.

매개변수로 테이블, 컬럼명, 예약어 등을 사용하는 특정 상황에서만 ${} 방식을 사용합니다.

Statement

// Statement

String userId = "userId"
String sql = "SELECT * FROM user WHERE id = " + userId
Statement stmt = conn.credateStatement();
ResultSet rst = stmt.executeQuerey(sql);
사용 예
// 코드
SELECT * FROM USER
WHERE id = "${id}"

SELECT * FROM USER
ORDER BY USER_ID ${sortOrder}
// 결과
SELECT * FROM USER
WHERE id = ?

SELECT * FROM USER
ORDER BY USER_ID DESC

#{sortOrder}를 사용하게된다면 ORDER BY USER_ID ‘DESC’ 형태로 실행이 되어 에러가 납니다.

Contents