🍃 Spring

🌻ORM, MyBatis : SQL과 자바의 역할 분리

보배 진 2026. 2. 9. 10:43

응집도를 높히고, 결합도를 낮추기 위해 사용

 

MyBatis

DAO를 Service가 사용하고 있는데 Service를 보면 이전에 만든 PlusMemberDAO가 의존주입되어 있는데

@Autowired

private MybatisMemberDAO memberDAO;

이렇게 새로 업그레이드하려는 MyBatisMemberDAO로 의존 주입을 해줘야 한다

 

 

 

 

SQL과 자바의 역할 분리를 위한 선택

private static final String SELECT_ALL = "SELECT * FROM MEMBER";
private static final String SELECT_ONE = "SELECT * FROM MEMBER WHERE MID=? AND MPW=?";
private static final String INSERT = "INSERT INTO MEMBER VALUES(?,?,?,'USER')";
private static final String UPDATE = "UPDATE MEMBER SET MNAME=? WHERE MID=?";
private static final String DELETE = "DELETE FROM MEMBER WHERE MID=?";

JAVA에서 데이터베이스 작업을 할 때,

기존에는 DAO 안에 SQL문을 직접 작성하는 방식을 사용했다

예를 들어 회원 정보를 관리하는 DAO 코드를 보면 위와 같이 되어 있었다

 

이런 방식의 문제점은 명확하다

🔹 SQL이 자바 코드 안에 섞여 있다 : 코드 응집도가 낮다

🔹 SQL을 수정하려면 자바 코드도 봐야 한다 : 역할 분리가 제대로 이루어지지 않았다

🔹 현업에서는 SQL 개발자과 자바 개발자가 분리되어 있다 : 지금같은 코드는 효율성이 매우 낮다

결국 DAO 안에 SQL을 직접 작성하면

자바와 SQL이 강하게 결합되어 유지보수와 확장성이 떨어지게 된다

 

 

 

 

MyBatis를 선택하는 이유

MyBatis는 SQL을 XML 파일로 분리하고, Java 코드에서는 SQL의 위치와 파라미터만 참조하도록 해주는 프레임워크

🔹 응집도 향상 : SQL과 자바 코드가 분리되어 각각의 역할이 명확

🔹 결합도 낮춤 : SQL 변경 시 Java 코드를 거의 수정하지 않아도 됨

🔹 협업 최적화 : SQL 개발자와 자바 개발자가 역할에 맞게 작업 가능

 

 

 

Spring과 함께 MyBatis 사용하기

1. 의존성 추가

pom.xml에 MyBatis Spring Boot Starter를 추가하면,

Spring에서 MyBatis를 쉽게 사용가능하다

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

🔼 패키지를 먼저 pom.xml에 추가하면

.java 파일에서 import org.apache.ibatis.session.SqlSession; 이렇게 import 해서 사용가능하다

 

 

2. DAO 구조

Mybatis에서 제공하는 객체 SqlSession를 통해 SQL 실행을 할 수 있다

package com.example.biz.member.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.example.biz.member.MemberDTO;

@Repository
public class MybatisMemberDAO {
	@Autowired
private SqlSession sqlSession;
	
	public boolean insertMember(MemberDTO dto) {
		if(sqlSession.insert("어떤 SQL문을 사용할지", dto) <= 0) {
			return false;
		}
		return true;
	}
	public boolean updateMember(MemberDTO dto) {
		if(sqlSession.update("어떤 SQL문을 사용할지", dto) <= 0) {
			return false;
		}
		return true;
	}
	public boolean deleteMember(MemberDTO dto) {
		if(sqlSession.delete("어떤 SQL문을 사용할지", dto) <= 0) {
			return false;
		}
		return true;
	}
	
	public MemberDTO getMember(MemberDTO dto) {
		return sqlSession.selectOne("어떤 SQL문을 사용할지", dto);
	}
	public List<MemberDTO> getMemberList(MemberDTO dto){
		return sqlSession.selectList("어떤 SQL문을 사용할지");
	}
}

🔼 MybatisMemberDAO를 요약하면 이렇게 된다

"어떤 SQL문을 사용할지"에는 어떤파일.어떤 sql 문이야? 가 들어간다

좀 더 디테일하게는 네임페이스.아이디값이 된다

 

 

MyBatisMemberDAO 전체 코드

package com.example.biz.member.impl;

import java.util.List;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.example.biz.member.MemberDTO;

@Repository
public class MybatisMemberDAO {
	@Autowired
	private SqlSession sqlSession;
	private static final String NAMESPACE = "Member.";

	public boolean insertMember(MemberDTO dto) {
		if(sqlSession.insert(NAMESPACE+"insert", dto) <= 0) {
			return false;
		}
		return true;
	}
	public boolean updateMember(MemberDTO dto) {
		if(sqlSession.update(NAMESPACE+"update", dto) <= 0) {
			return false;
		}
		return true;
	}
	public boolean deleteMember(MemberDTO dto) {
		if(sqlSession.delete(NAMESPACE+"delete", dto) <= 0) {
			return false;
		}
		return true;
	}
	
	public MemberDTO getMember(MemberDTO dto) {
		return sqlSession.selectOne(NAMESPACE+"getOne", dto);
	}
	public List<MemberDTO> getMemberList(MemberDTO dto){
		return sqlSession.selectList(NAMESPACE+"getList");
	}
}

여기서 "Member.insert" 같은 문자열은 네임스페이스.아이디값으로, 나중에 XML에서 정의한 SQL을 참조한다

 

 

 

 

XML Mapper 파일

xml은 설정파일을 의미하기 때문에

별도의 폴더에 관리용 폴더를 만들고 그 안에 xml 파일을 생성한다

ex) 이름은 Member.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="Member">
	
		<insert id="insert" parameterType="memberDTO">
			INSERT INTO MEMBER
			VALUES(#{mid},#{mpw},#{mname},'USER')
		</insert>
		
		<update id="update">
			UPDATE MEMBER 
			SET	MNAME = #{mname}
			WHERE MID = #{mid}
		</update>
		
		<delete id="delete">
			DELETE FROM MEMBER 
			WHERE MID = #{mid}
		</delete>
		
		<select id="getOne" parameterType="memberDTO" resultType="memberDAO"> <!-- 어떤거 반환하는지 기재 -->
			SELECT * FROM MEMBER 
			WHERE MID= #{MID} 
			AND MPW= #{MPW}
		</select>
		
		<select id="getList" resultType="memberDTO">
			SELECT * FROM MEMBER
		</select>
	</mapper>

🔹 스키마 버전을 맞추었고, 최상위 요소가 mapper이다

🔹  SQL은 대문자, 자바는 소문자를 보통 사용한다

🔹  id=에 들어가는 값이 DAO에서 참조할 네임페이스.아이디값이다

🔹 parameterType과 resultType으로 입력과 출력 타입 지정

 

 

 

 

 

 

 

application.properties 설정해주기

spring에서 너 mapper 가지고 있다~ 설정을 해줘야 한다

classPath = src/main/resources

classPath의 mappers 안에 있는 모든 파일들이 .xml이야 별칭을 member로 사용하겠다고 명시해줘야 한다

 

mapper-locations와 type-aliases-package를 지정하면, Spring이 XML과 DTO를 자동으로 연결한다

mybatis.mapper-locations=classpath:mappers/*.xml

의미 : MyBatis가 SQL이 정의된 XML 파일을 어디서 찾아야 하는지 알려주는 설정

classpath : 프로젝트의 resources 폴더 기준으로 경로를 지정

mappers/*.xml : resources/mappers/ 안에 있는 모든 XML 파일을 찾아서 Mapper로 등록

즉, 이 설정 덕분에 MyBatis는 mappers 폴더 안의 XML 파일을 읽어서

DAO에서 SqlSession이나 Mapper 인터페이스를 사용할 수 있게 됨

 

 

mybatis.type-aliases-package=com.example.biz.member

의미 : XML에서 parameterType이나 resultType에 DTO 클래스를 쓸 때, 패키지 전체를 스캔해서 별칭(alias)을 자동으로 등록해주는 설정

예를 들어 MemberDTO 클래스에 @Alias("memberDTO")를 붙이면 XML에서 

별칭으로 사용가능해진다

 

 

 

 

DTO에도 @Alias 사용

package com.example.biz.member;

import org.apache.ibatis.type.Alias;

@Alias("memberDTO")
public class MemberDTO {
	private String mid;
	private String mpw;
	private String mname;
	private String mrole;
	public String getMid() {
		return mid;
	}
	public void setMid(String mid) {
		this.mid = mid;
	}
	public String getMpw() {
		return mpw;
	}
	public void setMpw(String mpw) {
		this.mpw = mpw;
	}
	public String getMname() {
		return mname;
	}
	public void setMname(String mname) {
		this.mname = mname;
	}
	public String getMrole() {
		return mrole;
	}
	public void setMrole(String mrole) {
		this.mrole = mrole;
	}
	@Override
	public String toString() {
		return "MemberDTO [mid=" + mid + ", mpw=" + mpw + ", mname=" + mname + ", mrole=" + mrole + "]";
	}
}

DTO에도 어노테이션을 추가한다

별칭을 달아주었다 @Alias("memberDTO")

MyBatis에서 DTO를 XML과 연결할 때 별칭을 달면 코드가 더 깔끔해진다