티스토리 뷰

반응형

mybatis

이번 시간에는 MyBatis-Spring-Boot-Starter 의 사용법에 대해 알아보겠습니다. MyBatis-Spring-Boot-Starter(http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/)를 참고했습니다. 다른 참고 문헌은 페이지 하단에 소개되어있습니다.

바쁘신 분들은 <mybatis-spring-boot-autoconfigure 간략 설명 > 부터 참고하세요. 

사용 라이브러리

  • lombok
  • org.mybatis.spring.boot
  • mybatis
  • spring-boot
  • mysql

MyBatis란?

마이바티스는 개발자가 지정한 SQL , 저장 프로시저, 그리고 몇 가지 고급 매핑을 지원하는 퍼시스턴스 프레임워크입니다. 마이바이트는 JDBC 로 처리하는 상당 부분의 코드와 파라미터 설정, 결과 매핑을 대신해줍니다.

  • 저장 프로시저란, 일련의 쿼리를 하나의 함수처럼 실행하기 위한 쿼리의 집합이다.(위키백과)
  • 퍼시스턴스 프레임워크: 데이터의 CRUD 를 다루는 클래스 및 설정 파일들의 집합이다. 사용시, JDBC 프로그래밍의 복잡함이나 번거로움 없이 간단한 작업으로 데이터베이스와 연동되는 시스템을 빠르게 개발할 수 있다.(위키 백과)

MyBatis-Spring 은 무엇일까?

마이바티스 스프링 연동모듈은 마이바티스와 스프링을 편하고 간단하게 연동한다.

MyBatis-Spring 의 효과

  • 마이바티스가 스프링 트랜잭션에 쉽게 연동되도록 처리한다.
  • 마이바티스 매퍼와 SqlSession을 다루고 다른 빈에 주입시켜준다.
  • 마이바티스 예외를 스프링의 DataAccessException로 변환한다.
  • 마이바티스, 스프링 또는 마이바티스 스프링 연동모듈에 의존성을 없앤다.

MyBatis 를 Spring 과 함께 사용하기 위한 필수 요소

코드 : http://mybatis.org/spring/ko/getting-started.html

SqlSessionFactory

  • Mysql 서버와 MyBatis를 연결해주는건 SqlSessionFactory 객체이다. 데이터베이스와의 연결과 SQL의 실행에 대한 모든 것을 가지고있다.
  • 이 객체가 DataSource를 참조하여 MyBatis와 Mysql 서버를 연동시켜준다.
  • SqlSessionFactoryDataSource를 필요로 한다. 어떤 DataSource도 상관없지만 다른 스프링의 데이터베이스 연결과 동일하게 설정되어야 한다.

매퍼(Mapper)

  • Mybatis 매핑(어노테이션 혹은 xml 파일)에 기재된 SQL을 호출하기 위한 인터페이스이다.
  • 매퍼는 반드시 구현체 클래스가 아닌 인터페이스로 정의되어야 한다.
  • 한번만 설정하면, 다른 스프링 빈에 주입하는 같은 방법으로 비즈니스/서비스 객체에 매퍼를 직접 주입할 수 있다.
  • 실행중인 스프링 트랜잭션이 있다면, 트랜잭션이 완료되는 시점에 커밋이나 롤백이 될 것이다. 마지막으로 예외가 발생하면 스프링의 DataAccessException예외가 발생한다.

mybatis-spring-boot-autoconfigure 간략 설명

MyBatis-Spring-Boot-Starter를 사용하면 스프링부트 위에 MyBatis 애플리케이션을 빠르게 빌드 할 수 있습니다 .

MyBatis-Spring-Boot-Starter 효과

@Mapper 생성외의 다른 필수 작업들 ( 기존에 사용자가 설정해줘야 했던 SqlSessionFactory 등등.. ) 을 자동으로 해줍니다.

우리는 간단한 설정만 하면, 코 풀고 @Mapper 만 쓰면서 룰루랄라 mybatis 를 쓸 수 있습니다.

  • DataSource 를 자동 감지합니다.

  • SqlSessionFactory 를 전달 하는 인스턴스를 자동 생성하고 등록합니다

  • DataSource.SqlSessionFactoryBean 의 인스턴스를 만들고 등록합니다.

  • @Mapper주석이 표시된 매퍼를 자동 스캔하고에 연결합니다.

  • SqlSessionTemplateSpring 컨텍스트에 등록하여 Bean에 주입 할 수 있도록합니다.

메이븐 설정

코드는 (http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/) 를 참고했습니다.

  • pom.xml

      <dependency> 
          <groupId> org.mybatis.spring.boot </ groupId> 
          <artifactId> mybatis-spring-boot-starter </ artifactId> 
          <version> 2.1.3 </ version> 
      </dependency>

구성

application.properties(또는 application.yml) 안에 저장됩니다.

그 외의 구체적인 사항은 http://mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/ 를 참고하면 됩니다.


예제

dependency (maven)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.4.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com</groupId>
    <artifactId>giftclub</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>giftclub</name>
    <description>GiftClub project for Spring Boot</description>
    <properties>
        <java.version>11</java.version>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.5</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.4</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>


    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

mysql 세팅

mybatis 에서 사용할 데이터베이스(giftclub)와 테이블을 생성해줍니다. ( 사용한 sql 문은 따로 저장해두는 것이 좋습니다. )

drop table  IF EXISTS shop;
create table shop(
id INTEGER AUTO_INCREMENT PRIMARY KEY,
name VARCHAR(128),
description VARCHAR(128),
INDEX (name)
);
drop table IF EXISTS product;
create table product(
id INTEGER AUTO_INCREMENT PRIMARY KEY,
shop_id INTEGER ,
name VARCHAR(128),
price INTEGER,
discount INTEGER,
description VARCHAR(128),
INDEX (name),
FOREIGN KEY(shop_id)REFERENCES shop(id)
);

환경 설정

application.properties 에 내가 사용할 데이터베이스 세팅을 해줍니다.

server.port=8080 
server.servlet.context-path=/
spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/[데이터베이스명]?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Seoul
spring.datasource.username=[데이터베이스아이디]
spring.datasource.password=[데이터베이스비밀번호]
logging.level.com.giftclub=TRACE 

logging.level.com.giftclub=TRACE : 디비 쿼리를 로깅해주는 설정

로깅을 패키지 단위로 나오게 한다. 약한 버전 DEBUG ( 리턴 버전 o : TRACE, x: DEBUG)

server.port=8080 : 8080포트를 이용합니다.

data 설정

내가 사용하는 데이터를 설정해 줍니다.

  • lombok 의 @Data 어노테이션을 이용해 getter와 setter 를 자동 생성합니다.
package com.giftclub.shop;

import com.giftclub.product.Product;
import lombok.Data;

import java.util.List;

@Data
public class Shop {
    private int id;
    private String name;
    private String description;
    private List<Product> productList;
}
package com.giftclub.product;

import lombok.Data;

@Data
public class Product {
    private int id;
    private int shopId;
    private String name;
    private String description;
    private int price;
    private int discount;
}

mapper 생성

  • mapper interface 를 생성합니다. @Mapper 어노테이션을 이용하면, mapper 로 지정이 됩니다.
  • 어노테이션들에 대한 자세한 설명은 https://mybatis.org/mybatis-3/ja/apidocs/org/apache/ibatis/annotations/Results.html 로 가면 됩니다.
  • sql 쿼리를 의미하는 어노테이션들: @Insert, @Select,@Update,@Delete
  • @Options(useGeneratedKeys = true, keyProperty = "id") : 생성된 키를 가지고, "id" 에 대한 property 를 주는 역할을 수행한다.
  • @Param : sql 문의 변수로 들어간다.
  • @Results: result 를 표기하기 위한 방법을 표기한다.
    • 필드명 수정 : @Result(property = "name", column = "user_name"): DB의 user_name 을 name으로 수정해 표현
    • 아이디 지정: @ResultMap("CompanyMap") 형태로 후에 재사용 가능하다.
    • nested query: 추가로 외래키의 항목을 불러올 수 있다. @Result(property = "productList", column = "id", many = @Many(select = "com.giftclub.product.ProductMapper.getByShopId"))
    • @Result(property = "id", column = "id", id = true), nested query에서 사용한 필드값이 표시되게 한다.
package com.giftclub.shop;

import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface ShopMapper {
    final String getAll = "SELECT * FROM shop";
    final String getById = "SELECT * FROM shop WHERE id=#{id}";
    final String deleteById = "DELETE from shop WHERE id= #{id}";
    final String insert = "INSERT INTO shop(name, description) VALUES(#{shop.name}, #{shop.description})";
    final String update = "UPDATE shop SET name = #{shop.name}, description = #{shop.description} WHERE id= #{shop.id}";

    @Insert(insert)
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(@Param("shop") Shop shop);

    @Select("SELECT * FROM shop")
    @Results(id = "shopMapper", value = {
            @Result(property = "id", column = "id", id = true),
            @Result(property = "productList", column = "id", many = @Many(select = "com.giftclub.product.ProductMapper.getByShopId")),
    })
    List<Shop> getAll();

    @Select(getById)
    @ResultMap("shopMapper")
    Shop getById(@Param("id") int id);

    @Update(update)
    int update(@Param("shop") Shop shop);

    @Delete(deleteById)
    void deleteById(@Param("id") int id);

}
package com.giftclub.product;

import org.apache.ibatis.annotations.*;

import java.util.List;


@Mapper
public interface ProductMapper {
    final String insert = "INSERT INTO product(name,shop_id, description,discount,price) VALUES(#{product.name},#{product.shopId}, #{product.description},#{product.discount},#{product.price})";
    final String select = "SELECT * FROM product";
    final String getById = "SELECT * FROM product WHERE id=#{id}";
    final String getByShopId = "SELECT * FROM product WHERE shop_id=#{shopId}";


    @Insert(insert)
    @Options(useGeneratedKeys = true, keyProperty = "id")
    int insert(@Param("product") Product product);


    @Select(select)
    @Results(id = "productMap",
            value = {@Result(property = "shopId", column = "shop_id")})
    List<Product> getAll();

    @Select(getById)
    @ResultMap("productMap")
    Product getById(@Param("id") int id);


    @Select(getByShopId)
    @ResultMap("productMap")
    List<Product> getByShopId(@Param("shopId") int shopId);


}

Controller 설정


package com.giftclub.user;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(value = "/user")
public class UserController {
    @Autowired
    private UserMapper userMapper;

    @PostMapping("")
    public User post(@RequestBody User user) {
        userMapper.insert(user);
        return user;
    }

    @GetMapping("")
    public List<User> getAll() {
        return userMapper.getAll();
    }

    @GetMapping("/{id}")
    public User getById(@PathVariable("id") int id) {
        return userMapper.getById(id);
    }
}
package com.giftclub.product;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping(value = "/product")
public class ProductController {
    @Autowired
    private ProductMapper productMapper;

    @PostMapping("")
    public Product post(@RequestBody Product product) {
        productMapper.insert(product);
        return product;
    }

    @GetMapping("")
    public List<Product> getAll() {
        return productMapper.getAll();
    }

    @GetMapping("/{id}")
    public Product getById(@PathVariable("id") int id) {
        return productMapper.getById(id);
    }
}


참고 문헌

반응형
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함