MyBatis 개요 이후로 활용을 해보려고 한다.
xml로 할 것이며, TransactionFactory, DataSource 와 같은 것들도 사용해보자.
쿼리를 꺼내는 작업으로 사용하기 위해 활용할 Mapper 인터페이스
import org.apache.ibatis.annotations.Select;
import java.util.Date;
public interface Mapper {
@Select("SELECT NOW()")
Date selectNow();
}
Application
public class Application {
private static String driver = "com.mysql.cj.jdbc.Driver";
private static String url = "jdbc:mysql://localhost:3306/menudb";
private static String user = "swcamp";
private static String password = "swcamp";
public static void main(String[] args) {
Environment environment = new Environment("dev", new JdbcTransactionFactory(), new PooledDataSource(driver, url, user, password));
// configuration은 설계도
Configuration configuration = new Configuration(environment);
configuration.addMapper(Mapper.class);
// 설계도를 줄테니 공장을 지어달라는 의미로 사용
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(configuration);
// 이제 수동 커밋을 해야 한다. false를 해야지 수동 커밋이 된다.
SqlSession sqlSession = sqlSessionFactory.openSession(false);
// 쿼리를 꺼내는 작업
Mapper mapper = sqlSession.getMapper(Mapper.class);
Date date = mapper.selectNow();
System.out.println("date = " + date);
sqlSession.close();
}
}
이전부터 사용했던 menudb를 그대로 사용해보았고
Mapper 인터페이스와 Application은 같은 패키지에 넣어뒀다.
같은 이름이 있긴 한데 import 할 필요 없다.
JdbcTransactionFactory: 수동 커밋ManagedTransactionFactory: 자동 커밋
PooledDataSource: ConnectionPool 사용UnPooledDataSource: ConnectionPool 미사용
출력결과

설정 정보를 작성하기 위해서 mybatis-config.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">
DOCTYPE으로 설정하는 내용은 하위에 사용 가능한 태그, 속성들이 정의되어 있는 파일이다.<configuration>을 작성해주면 된다.<?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>
. . .
</configuration>
MyBatis에서 연동할 DB 정보를 등록하는 것으로, <environments> 태그는 여러 개의 <environment> 태그를 포함할 수 있으며, default 속성으로 기본 사용할 환경 설정을 지정할 수 있다.
<environment> 내부에는 <transactionManager>, <dataSource>, <property> 와 같이 여러 가지 태그가 들어갈 수 있다.
<transactionManager> : 트랜잭션 매니저를 JDBC 혹은 MANAGED로 설정할 수 있다.
<dataSource> : 속성으로 커넥션풀 사용 여부를 POOLED와 UNPOOLED로 설정할 수 있다.
| 구분 | POOLED | UNPOOLED |
|---|---|---|
| 특징 | 최초 Connection 객체 생성 시 해당 정보를 pool 영역에 저장해 두고 이후 Connection 객체를 생성할 때 이를 재사용한다. | Connection 객체를 별도로 저장하지 않고, 호출 시마다 매번 생성하여 사용한다. |
| 장점 | Connection 객체를 생성하여 데이터베이스와 연결을 구축하는데 걸리는 시간이 단축된다. | Connection 연결이 많지 않은 코드를 작성할 때 간단하게 구현할 수 있다. |
| 단점 | 단순한 로직을 수행하는 객체를 만들기에는 설정해야 할 정보가 많다. | 매번 새로운 Connection 객체를 생성하므로 속도가 상대적으로 느리다. |
"file:d:\"로 시작하는 경로를 기술하면 된다.<properties> 태그 안쪽에 <property> 태그를 작성하여 properties 파일에 값을 설정할 수 있다.위에 작성한 몇 가지 XML Tag 들을 사용해서 예제를 만들 것이다.
이전에 사용했던 menudb 로 할 것이고, MyBatis를 사용하기 위해서는 mapper, config 파일이 필요하다.
resources 폴더에 추가
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/menudb"/>
<property name="username" value="swcamp"/>
<property name="password" value="swcamp"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper.xml"/>
</mappers>
</configuration>
mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mapper">
<select id="selectNow" resultType="java.util.Date">
SELECT NOW()
</select>
</mapper>
Application 클래스
public class Application {
public static void main(String[] args) {
String resource = "mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
// 커넥션 객체를 session이라고 할 뿐이다. + 수동 커밋
SqlSession session = sqlSessionFactory.openSession(false);
// 여기서 꼭 소속과 id가 필요하다. 그래서 mapper.xml에 네임스페이스를 적어준 것이다. 소속이 필요해서.
Date date = session.selectOne("mapper.selectNow");
System.out.println("date = " + date);
session.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
주석에도 적혀있지만 mapper.xml에 <select> 부분을 보면 name도 같이 적혀 있다.
소속과 id가 있어야 selectOne()을 사용할 수 있는 것이다.
출력 결과

xml 파일에 DB에 적어둔 것들을 resultMap에 컬럼들을 정의해두고 <select> 를 통해서 원하는 쿼리 처리를 하는 방식으로 사용해보려고 한다.
새로운 프로젝트로 한다.
MenuDTO
package com.ohgiraffers.section01.xmlconfig;
public class MenuDTO {
private int menuCode;
private String menuName;
private int menuPrice;
private int categoryCode;
private String orderableStatus;
public MenuDTO() {
}
public MenuDTO(int menuCode, String menuNmae, int menuPrice, int categoryCode, String orderableStatus) {
this.menuCode = menuCode;
this.menuName = menuNmae;
this.menuPrice = menuPrice;
this.categoryCode = categoryCode;
this.orderableStatus = orderableStatus;
}
(getter, setter 코드 길어서 생략)
@Override
public String toString() {
return "MenuDTO{" +
"menuCode=" + menuCode +
", menuName='" + menuName + '\'' +
", menuPrice=" + menuPrice +
", categoryCode=" + categoryCode +
", orderableStatus='" + orderableStatus + '\'' +
'}';
}
}
mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/menudb"/>
<property name="username" value="swcamp"/>
<property name="password" value="swcamp"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="com/jehun/section01/xmlconfig/menu-mapper.xml"/>
</mappers>
</configuration>
menu-mapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="MenuMapper">
<resultMap id="menuResultMap" type="com.jehun.section01.xmlconfig.MenuDTO">
<id property="menuCode" column="MENU_CODE"/>
<result property="menuName" column="MENU_NAME"/>
<result property="menuPrice" column="MENU_PRICE"/>
<result property="categoryCode" column="CATEGORY_CODE"/>
<result property="orderableStatus" column="ORDERABLE_STATUS"/>
</resultMap>
</mapper>
기본 세팅의 Application
public class Application {
public static void main(String[] args) {
MenuController menuController = new MenuController();
Scanner sc = new Scanner(System.in);
do{
System.out.println("===== 메뉴 관리 =====");
System.out.println("1. 메뉴 전체 조회");
System.out.println("2. 메뉴 코드로 메뉴 조회");
System.out.println("3. 신규 메뉴 추가");
System.out.println("4. 메뉴 수정");
System.out.println("5. 메뉴 삭제");
System.out.println("9. 프로그램 종료");
System.out.print("메뉴 관리 번호를 입력하세요 : ");
int num = sc.nextInt();
switch(num) {
case 1: break;
case 9:
System.out.println("프로그램을 종료하겠습니다."); return;
default:
System.out.println("번호를 잘못 입력하셨습니다.");
}
} while (true);
}
}
이제 case문에 1,2,3,4,5번을 다 추가할 것이다.
필요한 클래스들은 Controller, Service, DAO에 값을 사용하려면 DTO도 필요하기에 위에 작성해뒀다.
그리고 xml을 읽을 Template 클래스, 결과를 반환해줄 PrintResult 클래스가 필요하다.
총 6개의 클래스가 필요하다는 뜻이다.
xml을 읽을 Template 클래스
public class Template {
private static SqlSessionFactory sqlSessionFactory;
public static SqlSession getSqlSession() {
if (sqlSessionFactory == null) {
String resource = "com/jehun/section01/xmlconfig/mybatis-config.xml";
try {
InputStream inputStream = Resources.getResourceAsStream(resource);
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return sqlSessionFactory.openSession(false);
}
}
1번부터 한 번 해보자.
일단 필요한건 Controller에서 알맞은 메소드를 호출하는 것이다.
그럼 Controller는 Service를 의존성 주입하면서 해당하는 메소드를 또 호출할 것이고,
Service 또한 DAO를 의존성 주입한 뒤 호출할 것이다.
코드를 보자.
Application의 switch 문 case 1에 추가
기존 코드
switch(num) {
case 1:
menuController.findAllMenus();
break;
case 9:
기존 코드
MenuController 코드
public class MenuController {
private final MenuService menuService;
private final PrintResult printResult;
public MenuController() {
menuService = new MenuService();
printResult = new PrintResult();
}
public void findAllMenus() {
List<MenuDTO> menusList = menuService.findAllMenus();
if (!menusList.isEmpty()) {
printResult.printMenus(menusList);
} else {
printResult.printErrorMessage("조회할 메뉴가 없습니다.");
}
}
}
기본 생성자에 Service와 printResult를 의존성 주입한다.
printResult는 반환(메시지 출력) 해주는 클래스이다.
이제 2,3,4,5 번이 추가되면서는 findAllMenus() 메소드 아래에 계속 추가될 예정이다.
MenuService 코드
import static com.jehun.section01.xmlconfig.Template.getSqlSession;
public class MenuService {
private final MenuDAO menuDAO;
public MenuService() {
menuDAO = new MenuDAO();
}
public List<MenuDTO> findAllMenus() {
SqlSession sqlSession = getSqlSession();
List<MenuDTO> menuList = menuDAO.selectAllMenus(sqlSession);
return menuList;
}
}
Service는 비즈니스 로직이기도 하고, 해당 xml 파일을 읽어오는 Template 클래스의 getSqlSession()을 불러온다.
MenuDAO
public class MenuDAO {
public List<MenuDTO> selectAllMenus(SqlSession sqlSession) {
return sqlSession.selectList("MenuMapper.selectAllMenus");
}
}
sqlSession을 비즈니스 로직으로부터 매개변수로 받아서 MenuMapper.xml의 selectAllMenus 쿼리를 리스트로 받아오는 것이 MenuDAO가 한 일이며
그것을 Service가 받아와서 반환해주면 컨트롤러는 출력을 해준다.
만약 비어있으면 조회할 메뉴가 없다면서 에러 메세지라고 출력해주게 된다.
최종 출력 결과

기존 Application 코드에 2번 case 문을 추가해주자.
Application
case 2:
System.out.print("조회하고 싶은 메뉴 코드를 입력하세요 : ");
int code = sc.nextInt();
menuController.findByMenuCode(code);
break;
Controller의 findByMenuCode()에 메뉴코드를 입력받는 메소드를 활용해서 넣어주려고 한다.
뭐 입력받는 부분을 메소드로 따로 빼도 괜찮다.
Controller 도 위의 전체 메뉴 조회와 크게 다르지 않다. 그냥 DTO 자체로 받아오느냐, List로 받느냐의 차이일 뿐이다.
Controller
기존 코드에 추가
public void findByMenuCode(int code) {
MenuDTO menuDTO = menuService.findByMenuCode(code);
if (menuDTO != null) {
printResult.printMenu(menuDTO);
} else {
printResult.printErrorMessage("해당 코드로 조회된 메뉴가 없습니다.");
}
}
Service 의존성 주입한 뒤 원하는 메뉴가 없다면 조회되는게 없다는 식으로 했다.
있다면 printMenu가 실행되게 했다.
printResult 에 추가
public void printMenu(MenuDTO menuDTO) {
System.out.println("해당 코드의 메뉴");
System.out.println(menuDTO);
}
MenuService에 추가
public MenuDTO findByMenuCode(int menuCode) {
SqlSession sqlSession = getSqlSession();
MenuDTO menuDTO = menuDAO.selectMenuByMenuCode(sqlSession, menuCode);
sqlSession.close();
return menuDTO;
}
여기서 사용할 SqlSession은 이제 menu-mapper.xml 속에 selectMenuByMenuCode 쿼리를 추가해서 사용할 것이다.
MenuDAO에 추가
public MenuDTO selectMenuByMenuCode(SqlSession sqlSession, int menuCode) {
return sqlSession.selectOne("MenuMapper.selectMenuByMenuCode", menuCode);
}
menu-mapper.xml 에 추가
<select id="selectMenuByMenuCode" resultMap="menuResultMap" parameterType="_int">
SELECT
MENU_CODE
, MENU_NAME
, MENU_PRICE
, CATEGORY_CODE
, ORDERABLE_STATUS
FROM TBL_MENU
WHERE MENU_CODE = #{ menuCode }
</select>
MyBatis를 사용할 때는 정수와 같은 것들을 입력받아서 사용할 때 parameterType="_int" 해당 부분과 #{ menuCode } 이런 형태로 작성해야 한다고 한다..
최종 출력 결과

Application에 case문 추가
case 3:
menuController.registerMenu(inputMenu());
inputMenu 메소드도 Application에 작성
private static Map<String, String> inputMenu() {
Scanner sc = new Scanner(System.in);
System.out.print("신규 메뉴의 이름을 입력해 주세요 : ");
String menuName = sc.nextLine();
System.out.print("신규 메뉴의 가격을 입력해 주세요 : ");
String menuPrice = sc.nextLine();
System.out.print("신규 메뉴의 카테고리 코드를 입력해 주세요 : ");
String categoryCode = sc.nextLine();
Map<String, String> parameter = new HashMap<>();
parameter.put("menuName", menuName);
parameter.put("menuPrice", menuPrice);
parameter.put("categoryCode", categoryCode);
return parameter;
}
각각 이름과 숫자여서 String, int 형이라 다르게 받는 것보다 map에 key, value로 나눠서 일단 String으로 저장한 뒤 바꿔줄 생각으로 작성했다.
Controller의 registerMenu 메소드
기존 코드에 추가
public void registerMenu(Map<String, String> parameter) {
// 가공처리는 컨트롤러의 역할 (이름, 코드, 카테고리 코드같은 다양한 자료형의 값들을 파싱해 하나의 타입으로)
String menuName = parameter.get("menuName");
int menuPrice = Integer.parseInt(parameter.get("menuPrice"));
int categoryCode = Integer.parseInt(parameter.get("categoryCode"));
MenuDTO menuDTO = new MenuDTO();
menuDTO.setMenuName(menuName);
menuDTO.setMenuPrice(menuPrice);
menuDTO.setCategoryCode(categoryCode);
if (menuService.registerMenu(menuDTO)) {
printResult.printSuccessMessage("register");
} else {
printResult.printErrorMessage("메뉴 추가 실패..");
}
여기서 printResult의 printSuccessMessage 는 각 메시지에 따라 신규 메뉴 추가, 메뉴 수정, 메뉴 삭제 이 중에서 선택해서 그 때마다 다른 메시지가 나오게 하려고 한다.
일단은 메뉴 추가를 하고 있기 때문에 등록만 작성하고 수정, 삭제는 세팅만 해두려고 한다.
printResult의 printSuccesssMessage
/* DML 작업 메소드 : insert, update, delete 작업 성공 시 해당 성공 메시지 출력용 메소드 */
public void printSuccessMessage(String message) {
String successMessage = "";
switch (message) {
case "register" :
successMessage = "신규 메뉴 등록에 성공하였습니다.";
break;
case "modify" :
break;
case "remove" :
break;
}
System.out.println("successMessage = " + successMessage);
}
다음은 서비스이다.
서비스의 registerMenu를 보자.
MenuService에 추가
public boolean registerMenu(MenuDTO menuDTO) {
SqlSession sqlSession = getSqlSession();
int result = menuDAO.insertMenu(sqlSession, menuDTO);
if (result > 0) sqlSession.commit();
else sqlSession.rollback();
sqlSession.close();
return result > 0 ? true : false;
}
여기서 result를 boolean 값을 통해서 하려고 했으나, 기존 MyBatis의 SqlSession 속에 있는 insert 메소드가 int형으로 반환을 해준다.

그래서 int형으로 받아서 크기에 따라 커지면 등록이 된 것이고, 아니면 안 된 것이기 때문에 삼항 연산자를 통해서 나타내봤다.
MenuDAO에도 insertMenu 메소드를 추가해줬다.
public int insertMenu(SqlSession sqlSession, MenuDTO menuDTO) {
return sqlSession.insert("MenuMapper.insertMenu", menuDTO);
}
menu-mapper.xml 에도 insert문 추가
<insert id="insertMenu" parameterType="com.jehun.section01.xmlconfig.MenuDTO">
INSERT
INTO TBL_MENU
(
MENU_NAME
, MENU_PRICE
, CATEGORY_CODE
, ORDERABLE_STATUS
)
VALUES
(
#{ menuName }
, #{ menuPrice }
, #{ categoryCode }
, 'Y'
)
</insert>
이런 식으로 해서 최종 출력까지 하면 등록도 잘 된다.
하지만 auto-increment로 되어 있는 menu_code로 인해 메뉴 번호는 지정하기 위해선 다른 조치가 필요하다. (일단은 생략할 것이다.)
원래는 4번, 5번으로 나눠야 하지만 그냥 같이 알아보려고 한다. 위의 흐름과 크게 다를건 없기 때문이다.
Application case문
case 4:
menuController.modifyMenu(inputModifyMenu());
break;
case 5:
System.out.print("삭제하고 싶은 메뉴 코드를 입력하세요 : ");
int deleteCode = sc.nextInt();
menuController.deleteMenu(deleteCode);
break;
메뉴 추가해주는 것처럼 inputModifyMenu() 메소드도 아래와 같이 Application에 추가해줬다.
private static Map<String, String> inputModifyMenu() {
Scanner sc = new Scanner(System.in);
System.out.print("변경할 메뉴의 메뉴 번호를 입력해 주세요 : ");
String menuCode = sc.nextLine();
System.out.print("변경할 메뉴의 이름을 입력해 주세요 : ");
String menuName = sc.nextLine();
System.out.print("변경할 메뉴의 가격 입력해 주세요 : ");
String menuPrice = sc.nextLine();
Map<String, String> parameter = new HashMap<>();
parameter.put("menuCode", menuCode);
parameter.put("menuName", menuName);
parameter.put("menuPrice", menuPrice);
return parameter;
}
Controller 에도 modifyMenu, deleteMenu 추가
public void modifyMenu(Map<String, String> parameter) {
int menuCode = Integer.parseInt(parameter.get("menuCode"));
String menuName = parameter.get("menuName");
int menuPrice = Integer.parseInt(parameter.get("menuPrice"));
MenuDTO menuDTO = new MenuDTO();
menuDTO.setMenuCode(menuCode);
menuDTO.setMenuName(menuName);
menuDTO.setMenuPrice(menuPrice);
if (menuService.modifyMenu(menuDTO)) {
printResult.printSuccessMessage("modify");
} else {
printResult.printErrorMessage("메뉴 추가 실패..");
}
}
public void deleteMenu(int deleteCode) {
if (menuService.deleteMenu(deleteCode)) {
printResult.printSuccessMessage("remove");
} else {
printResult.printErrorMessage("해당 코드로 조회된 메뉴가 없습니다.");
}
}
printResult의 성공했을 때의 메세지를 출력해주는 SuccessMessage case 문
case "modify" :
successMessage = "메뉴 수정에 성공하였습니다.";
break;
case "remove" :
successMessage = "메뉴 삭제에 성공하였습니다.";
break;
MenuDAO
public int modifyMenu(SqlSession sqlSession, MenuDTO menuDTO) {
return sqlSession.update("MenuMapper.modifyMenu", menuDTO);
}
public int deleteMenuByMenuCode(SqlSession sqlSession, int deleteCode) {
return sqlSession.delete("MenuMapper.deleteMenu", deleteCode);
}
menu-mapper.xml
<update id="modifyMenu" parameterType="com.ohgiraffers.section01.xmlconfig.MenuDTO">
UPDATE
TBL_MENU
SET
MENU_NAME = #{ menuName }
, MENU_PRICE = #{ menuPrice }
WHERE MENU_CODE = #{ menuCode }
</update>
<delete id="deleteMenu" parameterType="com.ohgiraffers.section01.xmlconfig.MenuDTO">
DELETE
FROM TBL_MENU
WHERE MENU_CODE = #{ menuCode }
</delete>
전부 다 잘 되는 것을 알 수 있었다.
이번에는 MenuMapper 라는 인터페이스에 어노테이션을 활용하여 menu-mapper.xml 의 역할과 DAO의 역할을 해주게끔 하는 2번째 예제를 다뤄볼 생각이다.
위의 코드들과 비교하면 DAO를 쓰지 않고, Service에서 MenuMapper를 불러와서 사용하는 것밖에 없다고 보면 된다.
MenuMapper 인터페이스는 DAO + Mapper 의 역할을 할 수도 있다.
/* DAO + Mapper 의 의미*/
public interface MenuMapper {
@Results(id="menuResultMap", value = {
@Result(id = true, property = "menuCode", column = "MENU_CODE"),
@Result(property = "menuName", column = "MENU_NAME"),
@Result(property = "menuPrice", column = "MENU_PRICE"),
@Result(property = "categoryCode", column = "CATEGORY_CODE"),
@Result(property = "orderableStatus", column = "ORDERABLE_STATUS")
})
@Select("SELECT\n" +
" MENU_CODE\n" +
" , MENU_NAME\n" +
" , MENU_PRICE\n" +
" , CATEGORY_CODE\n" +
" , ORDERABLE_STATUS\n" +
" FROM TBL_MENU")
List<MenuDTO> selectAllMenus();
@Select("SELECT\n" +
" MENU_CODE\n" +
" , MENU_NAME\n" +
" , MENU_PRICE\n" +
" , CATEGORY_CODE\n" +
" , ORDERABLE_STATUS\n" +
" FROM TBL_MENU\n" +
" WHERE MENU_CODE = #{menuCode}")
@ResultMap("menuResultMap")
MenuDTO selectMenu(int menuCode);
@Insert("""
INSERT
INTO TBL_MENU
(
MENU_NAME
, MENU_PRICE
, CATEGORY_CODE
, ORDERABLE_STATUS
)
VALUES
(
#{menuName}
, #{menuPrice}
, #{categoryCode}
, 'Y'
)
""")
int insertMenu(MenuDTO menu);
@Update("""
UPDATE
TBL_MENU
SET MENU_NAME = #{menuName}
, MENU_PRICE = #{menuPrice}
WHERE MENU_CODE = #{menuCode}
""")
int updateMenu(MenuDTO menu);
@Delete("""
DELETE
FROM TBL_MENU
WHERE MENU_CODE = #{menuCode}
""")
int deleteMenu(int menuCode);
}
이는 곧 xml에서 다뤘을 때의 쿼리들이 인텔리제이의 DML과 관련있는 어노테이션과 함께 사용한 것이다.
이 인터페이스를 Service에서 사용하는것과 마찬가지다 아래 코드를 같이 보자.
MenuService
public class MenuService {
private MenuMapper menuMapper;
// 메뉴 전체 조회
public List<MenuDTO> findAllMenus() {
SqlSession sqlSession = getSqlSession();
menuMapper = sqlSession.getMapper(MenuMapper.class);
List<MenuDTO> menuList = menuMapper.selectAllMenus();
sqlSession.close();
return menuList;
}
// 메뉴 단 건 조회
public MenuDTO findByMenuCode(int menuCode) {
SqlSession sqlSession = getSqlSession();
menuMapper = sqlSession.getMapper(MenuMapper.class);
MenuDTO menuDTO = menuMapper.selectMenu(menuCode);
sqlSession.close();
return menuDTO;
}
// 신규 메뉴 등록
public boolean registerMenu(MenuDTO menuDTO) {
SqlSession sqlSession = getSqlSession();
menuMapper = sqlSession.getMapper(MenuMapper.class);
int result = menuMapper.insertMenu(menuDTO);
if (result > 0) sqlSession.commit();
else sqlSession.rollback();
sqlSession.close();
return result > 0 ? true : false;
}
// 메뉴 수정
public boolean modifyMenu(MenuDTO menuDTO) {
SqlSession sqlSession = getSqlSession();
menuMapper = sqlSession.getMapper(MenuMapper.class);
int result = menuMapper.updateMenu(menuDTO);
if (result > 0) sqlSession.commit();
else sqlSession.rollback();
sqlSession.close();
return result > 0 ? true : false;
}
// 메뉴 삭제
public boolean deleteMenu(int deleteCode) {
SqlSession sqlSession = getSqlSession();
menuMapper = sqlSession.getMapper(MenuMapper.class);
int result = menuMapper.deleteMenu(deleteCode);
if (result > 0) sqlSession.commit();
else sqlSession.rollback();
sqlSession.close();
return result > 0 ? true : false;
}
}
잘 보면 그냥 쿼리만 불러올 뿐 똑같은 코드인거나 마찬가지이다..
인터페이스를 잘 보면 SELECT 를 제외한 DML은 사실 int형을 반환해준다.
그래서 result에서 int형으로 삼항 연산을 통해 잘 되는지 아닌지 확인할 수 있다.
한 가지 방법이 더 있다.
mapper 인터페이스를 DAO의 역할로만 사용하면서
위에서 처럼 xml에는 쿼리를 담아서 mapper 인터페이스의 메소드와 같은 이름의 id로 둔 다음 사용하는 방식이 있다.
Menumapper.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jehun.section03.remix.MenuMapper">
<resultMap id="menuResultMap" type="com.jehun.section03.remix.MenuDTO">
<id property="menuCode" column="MENU_CODE"/>
<result property="menuName" column="MENU_NAME"/>
<result property="menuPrice" column="MENU_PRICE"/>
<result property="categoryCode" column="CATEGORY_CODE"/>
<result property="orderableStatus" column="ORDERABLE_STATUS"/>
</resultMap>
<select id="selectAllMenus" resultMap="menuResultMap">
SELECT
MENU_CODE
, MENU_NAME
, MENU_PRICE
, CATEGORY_CODE
, ORDERABLE_STATUS
FROM TBL_MENU
</select>
(... 중략)
이 xml 파일에 쿼리가 들어가는데 다 같은 내용이라서 중략했다.
그럼 인터페이스는 어떻게 이뤄질까?
MenuMapper 인터페이스
public interface MenuMapper {
List<MenuDTO> selectAllMenus();
MenuDTO selectMenu(int menuCode);
int insertMenu(MenuDTO menu);
int updateMenu(MenuDTO menu);
int deleteMenu(int menuCode);
}
잘 보면 xml에 있는 <mapper> 와 <select> 태그에 인터페이스에 관해 매핑되어 있고, id 값도 인터페이스의 메소드와 같은 것을 알 수 있다.
그것으로 구분해서 사용할 수도 있다.