안녕하세요 코골면서 딩가딩가입니다. 😃😃😃 이번에는 Springboot - Mybatis 실습을 해보려고 합니다. 이번실습도 SQL을 실행하여 작업하기 때문에 JDBC Temlpate 공부는 필수입니다. 잘 모르시는분들은 이전 글 참고해주세요!
06. Spring - ★JDBCTemplate 연동★
+ 실습에 들어가기전에 ( ※ 이번실습은 매우매우 중요해서 정말 열심히 공부해보겠습니다. ※) (★★★★★★★★★★★ 중요 ★★★★★★★★★★★) 들어가기에 앞서, 이번 실습은 준비물
mom11230.tistory.com
그럼시작해보겠습니다!!! (●'◡'●)
✅ 00. MyBatis 흐름
이전 JDBC Template을 통해 SQL을 실행하였다면 MyBatis는 해당 흐름을 전용 라이브러리를 통해 대체하여 동작합니다.

✅ 01. MyBatis 동작 구조

MyBatis동작 구조입니다. 위에 그림에서 나온 DAO-Mybatis설정 파일에 대한 자세한 설명입니다. 보시고 참고하시면 좋을 것 같아요!
✅ 02. MyBatis 내장 별칭

MyBatis에서 사용되는 타입입니다. java랑 다른 타입을 사용하고 있으니 숙지하셔야 합니다.
✅ 03. mapper.xml 작성
가. 작성예시
MyBatis에서 mapper.xml 파일은 SQL 쿼리와 Java 메서드 간의 매핑을 정의하는 역할을 합니다. 이 파일은 SQL 매핑을 위한 XML 파일이며, MyBatis는 이를 사용하여 데이터베이스와 상호 작용합니다.
mapper.xml 파일에는 다음과 같은 내용이 포함될 수 있습니다:
1. SQL 쿼리: 데이터베이스에서 실행할 SQL 쿼리를 포함합니다.
2. 매개변수 매핑: SQL 쿼리의 매개변수를 Java 객체에 매핑하는 규칙을 정의합니다.
3. 결과 매핑: SQL 쿼리의 결과를 Java 객체에 매핑하는 규칙을 정의합니다.



이번 실습에서 .xml을 수정해 mybatis 를 사용할 수 있게 해주는 mapper.xml 작성 요령입니다. 실습을 하면서 다시 활용해보겠습니다.

나. 작성요령


mapper.xml 작성요령입니다. INSERT, UPDATE, DELETE 태그는 같은 설정값을 가지니 참고합시다!
✅ 04. <select>태그 주요 속성

<select> 태그의 주요 속성입니다. 마찬가지로 mapper에서 사용되는 주요 속성 명입니다. 암기합시다..!(저는 사실보면서 했어요~~헤헤)
✅ 05. Mybatis를 활용한 코드(쇼핑몰상품 Select / Update 해보기)
가. 개발 규격

이번 실습에서 개발할 규격입니다. goods(상품) TABLE 을 만들고 어노테이션을 사용하여 컴포넌트가 될 수 있게 만들며, mapper 클래스에 (select/insert/update) 가 사용될 수 있도록 설정합니다.(헤헤 지금 보니까 insert 문은 이번 실습에 사용 안했네 데헷🤣)
실습시작해보겠습니다..!
나. 구현 방법 (전체구성)
이번실습에서 사용한 환경입니다.
pakages : mybatis
org.kitri.springmybatis
org.kitri.springmybatis.controller
org.kitri.springmybatis.dao
org.kitri.springmybatis.dto
org.kitri.springmybatis.service
class : mybatis.xml → (요놈이 이번 Mybatis 실습에서 핵심인 mapper 역할을 합니다.)
RunMain.java
GoodsController.java
GoodsDao.java
GoodsDaoImpl.java
Goods.java
GoodsService.java
GoodsServiceImpl.java
xml : config.xml
pom.xml
Goods.xml

pakages : mybatis
Class : mybatis.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="org.kitri.springmybatis.dao.GoodsDao">
<select id="findAllGoods"
resultType="org.kitri.springmybatis.dto.Goods">
SELECT * FROM goods
</select>
<select id="findGoodsByProductCode" parameterType="String"
resultType="org.kitri.springmybatis.dto.Goods">
SELECT * FROM goods WHERE productCode = #{productCode}
</select>
<update id="updateQuantity" parameterType="map">
UPDATE goods SET
quantity = #{newQuantity} WHERE productCode = #{productCode}
</update>
<update id="updateProductStatus" parameterType="map">
UPDATE goods SET
productStatus = #{productStatus} WHERE productCode = #{productCode}
</update>
</mapper>
이번 실습에서 가장 중요한 내용이여서 먼저 다루어 보겠습니다. 위쪽에서 select 주요 태그 구성을 참고하여 다음과 같이 select 문을 만들어 봤습니다.
1. namespce 의 이름을 입력해서 외부에서로부터 접근할 수 있게 설정했습니다.
2. findAllGood : 모든 상품이 검색될 수 있는 select 문입니다.
3. findGoodsByProductCode : 상품코드를 인식할 수 있게 해주는 select 문입니다.
4. updateQuantity : quantity(상품수량)을 update 할 수 있게 해주는 문입니다.
5. updateProductStatus : productStatus(상품상태)를 update 할 수 있게 해주는 문입니다.
Class : pom.xml


<?xml version="1.0" encoding="UTF-8"?>
<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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.kitiri</groupId>
<artifactId>springmybatis</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>springcore</name>
<!-- FIXME change it to the project's website -->
<url>http://maven.apache.org</url>
<properties>
<springframework.version>4.3.6.RELEASE</springframework.version>
<javax.annotation.version>1.3.2</javax.annotation.version>
<junit.version>4.11</junit.version>
<springmybatis.version>2.0.5</springmybatis.version>
<mybatis.version>3.5.4</mybatis.version>
<apache.common.dbcp.version>2.7.0</apache.common.dbcp.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${springframework.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>${springmybatis.version}</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>${mybatis.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>${apache.common.dbcp.version}</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>${javax.annotation.version}</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.4</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<source>11</source>
<target>11</target>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
이번실습에서는 pom.xml에 mybatis가 적용될 수 있도록 추가해줘야 하며, 저는 추가로 외부 라이브러리랑 프레임워크도 가져오기 위해서 web도 사용했습니다.
pakages : org.kitri.springmybatis
Class : RunMain.java

package org.kitri.springmybatis;
import org.kitri.springmybatis.controller.GoodsController;
import org.kitri.springmybatis.dto.Goods;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;
import java.util.Scanner;
public class RunMain {
public static void main(String[] args) {
try {
// 스프링 컨테이너 생성
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:/config.xml");
// GoodsController 빈 객체를 가져옴
GoodsController goodsController = ctx.getBean(GoodsController.class);
// list 메서드 호출
List<Goods> goodsList = goodsController.list();
// 결과 출력
System.out.println("상품 목록:");
for (Goods goods : goodsList) {
System.out.println(goods);
}
// 상품 추가 희망 번호 입력
Scanner scanner = new Scanner(System.in);
System.out.print("문의하기(상품추가 희망시 코드번호입력): ");
String productCode = scanner.nextLine();
if ("004".equals(productCode) ) {
goodsController.updateQuantity();
// 상품 추가 후 목록 다시 출력
System.out.println("상품 추가 후 목록:");
goodsList = goodsController.list();
for (Goods goods : goodsList) {
System.out.println(goods);
}
} else {
System.out.println("해당 상품번호로 등록된 상품이 없습니다.");
}
// 스프링 컨테이너 소멸
ctx.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
main () 클래스 입니다. 외부 클래스로부터 상품 목록을 볼 수 있게 구현했으며, 문의하기를 통해 상품코드를 입력하면 ipdate되게 설정했습니다.(저는 004만 update 되게 구현해봤습니다.)
pakages : org.kitri.springmybatis.controller
Class : GoodsController.java

package org.kitri.springmybatis.controller;
import org.kitri.springmybatis.dto.Goods;
import org.kitri.springmybatis.service.GoodsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import java.util.List;
@Controller
@RequestMapping("/goods")
public class GoodsController {
@Autowired
private GoodsService goodsService;
@GetMapping("/list")
public List<Goods> list() {
return goodsService.findAllGoods();
}
@GetMapping("/updateQuantity")
public String updateQuantity() {
Goods goods = goodsService.findGoodsByProductCode("004");
if (goods != null) {
int newQuantity = goods.getQuantity() + 50;
goodsService.updateQuantity("004", newQuantity); // 상품 코드를 직접 전달
System.out.println("문의하신 상품의 수량을 증가시켰습니다.");
}
return "redirect:/goods/list";
}
}
마찬가지로 외부 클래스값을 받는 클래스입니다. 여기서는 GetMapping을 사용해서 이름을 정의한 다음 RunMain이 받을 수 있게 수정하였습니다. 또한, updateQuantity를 사용하여 상품코드004에 quantity(상품수량이) != null 이면 수량이 +50이 되도록 구현했습니다.
pakages :org.kitri.springmybatis.dao
Class : GoodsDao

package org.kitri.springmybatis.dao;
import org.kitri.springmybatis.dto.Goods;
import java.util.List;
public interface GoodsDao {
List<Goods> findAllGoods();
Goods findGoodsByProductCode(String productCode);
void updateQuantity(String productCode, int newQuantity);
void updateProductStatus(String productCode, String productStatus);
}
이 코드에서는 맨 처음 Good.xml 에서 mapping 해놓은 dao 클래스입니다. mybatis에서 정의해놓은 sql문을 받아주는 역할을 합니다.
Class : GoodsDaoImpl

package org.kitri.springmybatis.dao;
import org.apache.ibatis.session.SqlSession;
import org.kitri.springmybatis.dto.Goods;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Repository
public class GoodsDaoImpl implements GoodsDao {
@Autowired
private SqlSession sqlSession;
@Override
public List<Goods> findAllGoods() {
return sqlSession.selectList("org.kitri.springmybatis.dao.GoodsDao.findAllGoods");
}
@Override
public Goods findGoodsByProductCode(String productCode) {
return sqlSession.selectOne("org.kitri.springmybatis.dao.GoodsDao.findGoodsByProductCode", productCode);
}
@Override
public void updateQuantity(String productCode, int newQuantity) {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("productCode", productCode);
parameterMap.put("newQuantity", newQuantity);
sqlSession.update("org.kitri.springmybatis.dao.GoodsDao.updateQuantity", parameterMap);
}
@Override
public void updateProductStatus(String productCode, String productStatus) {
Map<String, Object> parameterMap = new HashMap<>();
parameterMap.put("productCode", productCode);
parameterMap.put("productStatus", productStatus);
sqlSession.update("org.kitri.springmybatis.dao.GoodsDao.updateProductStatus", parameterMap);
}
}
※ 여기가 바로 MyBatis 동작 구조 부분입니다. SqlSession 을 사용하여 SQL을 실행하고 결과를 매핑하게 해주는 역할을 해줍니다.
pakages :org.kitri.springmybatis.dto
Class : GoodsDto
package org.kitri.springmybatis.dto;
public class GoodsDto {
private String productCode;
private String productName;
private String productPrice;
private String manufacturer;
private String productStatus;
private int quantity;
public String getProductCode() {
return productCode;
}
public void setProductCode(String productCode) {
this.productCode = productCode;
}
public String getProductName() {
return productName;
}
public void setProductName(String productName) {
this.productName = productName;
}
public String getProductPrice() {
return productPrice;
}
public void setProductPrice(String productPrice) {
this.productPrice = productPrice;
}
public String getManufacturer() {
return manufacturer;
}
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getProductStatus() {
return productStatus;
}
public void setProductStatus(String productStatus) {
this.productStatus = productStatus;
}
public int getQuantity() {
return quantity;
}
public void setQuantity(int quantity) {
this.quantity = quantity;
}
@Override
public String toString() {
return "Goods{" + "productCode='" + productCode + '\'' + ", productName='" + productName + '\''
+ ", productPrice='" + productPrice + '\'' + ", manufacturer='" + manufacturer + '\''
+ ", productStatus='" + productStatus + '\'' + ", quantity=" + quantity + '}';
}
}
항상 사용되는 get,set 그리고 toString () 을 사용하는 dto 클래스입니다. 출력값이 나오는 부분을 구현해줍니다.
pakages : org.kitri.springmybatis.service
Class : GoodsService

package org.kitri.springmybatis.service;
import org.kitri.springmybatis.dto.GoodsDto;
import java.util.List;
public interface GoodsService {
List<GoodsDto> findAllGoods();
GoodsDto findGoodsByProductCode(String productCode);
void updateQuantity(String productCode, int newQuantity);
}
마찬가지로 외부 클래스를 받는 클래습니다.
Class : GoodsServiceImpl

package org.kitri.springmybatis.service;
import org.kitri.springmybatis.dao.GoodsDao;
import org.kitri.springmybatis.dto.GoodsDto;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
public class GoodsServiceImpl implements GoodsService {
@Autowired
private GoodsDao goodsDao;
@Override
public List<GoodsDto> findAllGoods() {
return goodsDao.findAllGoods();
}
@Override
public GoodsDto findGoodsByProductCode(String productCode) {
return goodsDao.findGoodsByProductCode(productCode);
}
@Override
@Transactional
public void updateQuantity(String productCode, int newQuantity) {
goodsDao.updateQuantity(productCode, newQuantity);
if (newQuantity > 0) {
goodsDao.updateProductStatus(productCode, "판매중");
} else {
goodsDao.updateProductStatus(productCode, "판매중지");
}
}
}
Dao 클래스의 값을 받는 클래스입니다. 여기서는 @Transactional 을 사용하여 트랜잭션을 시작하여 새로운 상품수량이 0보다 크면 상품상태가 판매중으로 나오게 설정했습니다.
Class : config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<context:component-scan
base-package="org.kitri.springmybatis" />
<bean id="dataSource"
class="org.apache.commons.dbcp2.BasicDataSource"
p:driverClassName="oracle.jdbc.OracleDriver"
p:url="jdbc:oracle:thin:@192.168.10.11:1521:DB19" p:username="dst04"
p:password="dst04" />
<bean class="org.mybatis.spring.SqlSessionFactoryBean"
name="sqlSessionFactoryBean" p:dataSource-ref="dataSource"
p:mapperLocations="classpath:/mybatis/*.xml"
p:typeAliasesPackage="org.kitri.springmybatis.dto" />
<bean class="org.mybatis.spring.SqlSessionTemplate"
name="sqlSessionTemplate"
c:sqlSessionFactory-ref="sqlSessionFactoryBean" />
</beans>
config.xml 파일입니다. 기존 실습과 동일하게 oracle 계정에 연동할수있게 해주고 하단에 mybatis 를 사용할 수 있게 해주는 sqlSession을 정의했습니다.
다. 실행
모든 코드가 드디어 구성되었습니다...(휴) 이제 SQL 문과 연동시켜서 결과값을 확인해봅시다.

다음은 goods(상품) TABLE 생성 SQL 문입니다.

Drop table goods;
CREATE TABLE goods (
productCode VARCHAR(20),
productName VARCHAR(20),
productPrice VARCHAR(20),
manufacturer VARCHAR(20),
productStatus VARCHAR(20),
quantity INT
);
INSERT INTO goods (productCode, productName, productPrice, manufacturer, productStatus, quantity)
VALUES ('001', '반팔 티셔츠', '25000', '나이키', '판매중', 100);
INSERT INTO goods (productCode, productName, productPrice, manufacturer, productStatus, quantity)
VALUES ('002', '청바지', '55000', '아디다스', '판매중', 80);
INSERT INTO goods (productCode, productName, productPrice, manufacturer, productStatus, quantity)
VALUES ('003', '긴팔 티셔츠', '45000', '퓨마', '판매중', 60);
INSERT INTO goods (productCode, productName, productPrice, manufacturer, productStatus, quantity)
VALUES ('004', '가디건', '65000', '르꼬끄', '판매중지', 0);
INSERT INTO goods (productCode, productName, productPrice, manufacturer, productStatus, quantity)
VALUES ('005', '신발', '105000', '반스', '판매중', 70);
select * from goods;
commit;
저는 상품코드 004의 수량을 0으로 설정해서 판매중지인 상태로 만들었습니다!
이제 코드 실행해보겠습니다.

정상적으로 작동하는게 보이며 상품의 목록이 전부 보이게 됩니다. 이때 004의 quantity = 0 이여서 현재 판매중지 상태입니다.

그래서 해당 상품코드인 "004"를 입력한 결과 수량이 50으로 증가 했으며, 상품상태도 판매중인것으로 바뀐것을 볼 수 있습니다.

'Spring' 카테고리의 다른 글
07. Spring - ★JDBCTemplate 연동(응용)★ (0) | 2024.04.24 |
---|---|
06. Spring - ★JDBCTemplate 연동★ (2) | 2024.04.23 |
05. Spring - Interface 주입 (2) | 2024.04.22 |
04. Spring- Auto Wiring(@Autowiring, @Qualifier) (3) | 2024.04.19 |
03. Spring- Properties (3) | 2024.04.18 |