본문 바로가기
Spring

[Spring] DB 연동 - MyBatis

by Amy IT 2022. 8. 27.

 

목차

     

    MyBatis 란?

    MyBatis(마이바티스)는 SQL 매핑(mapping) 프레임워크입니다. MyBatis는 JDBC로 처리하는 상당 부분의 코드와 파라미터 설정 및 결과 매핑을 대신해 줌으로써, 개발자가 복잡한 코드 작업을 피하고 좀 더 빠르게 SQL을 처리할 수 있도록 도와줍니다. JDBC의 기본적인 프로그래밍 구조와 비교했을 때 MyBatis의 장점은 다음과 같습니다.

     

    JDBC MyBatis
    Connection 직접 맺고 close() MyBatis 내부적으로 Connection 자동으로 맺고 close()
    PreparedStatement 직접 생성 및 처리 MyBatis 내부적으로 PreparedStatement 생성 및 처리
    PreparedStatement의 setXXX() 등 작업 직접 처리 #{prop}와 같이 속성 지정시 내부적으로 자동 처리
    ResultSet 직접 처리 리턴 타입 지정시 자동으로 객체 생성 및 ResultSet 처리

     

    MyBatis-Spring

    MyBatis-Spring 라이브러리는 MyBatis와 Spring을 편하고 간단하게 연동시켜 줍니다. 이 라이브러리는 MyBatis가 Spring 트랜잭션과 쉽게 연동되도록 하고 MyBatis의 매퍼, SqlSession을 build하여 다른 빈에 주입하는 등의 작업, MyBatis의 예외를 Spring의 DataAccessException으로 변환하는 작업 등을 합니다. 

     

    Spring 프로젝트에서 MyBatis를 사용하기 위한 환경설정과, MyBatis를 사용해 DB와 연동하는 예제를 살펴보도록 하겠습니다. 아래는 프로젝트의 구조입니다.

     

    실습을 위해 오라클 DBMS의 scott 계정에 test라는 테이블을 만들어 멤버를 조회하고 추가하는 등의 작업을 해 보도록 하겠습니다.

    create table test
    ( num number(4) primary key,
      username varchar2(10),
      address varchar2(10) );
    
    insert into test values ( 1, '홍길동' , '서울');
    insert into test values ( 2, '이순신' , '강원');
    insert into test values ( 3, '유관순' , '제주');
    insert into test values ( 4, '강감찬' , '서울');
    insert into test values ( 5, 'aaa' , 'aaa');
    commit;

     

     

    MyBatis 환경설정

    dependency 추가

    MyBatis를 이용한 DB 연동을 위해 필요한 라이브러리들을 pom.xml에 추가해 줍니다. 저는 MyBatis 라이브러리 두 가지와, Spring 데이터베이스 처리를 위한 JDBC 라이브러리, DataSource 사용을 위한 DBCP2 라이브러리, 오라클 DBMS와 연동하기 위한 오라클 라이브러리, 총 다섯 가지의 라이브러리를 추가했습니다.

    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.6</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.2</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.22.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-dbcp2 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-dbcp2</artifactId>
        <version>2.5.0</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/com.jslsolucoes/ojdbc6 -->
    <dependency>
        <groupId>com.jslsolucoes</groupId>
        <artifactId>ojdbc6</artifactId>
        <version>11.2.0.1.0</version>
    </dependency>

     

    properties 파일

    DB 연동을 위해 필요한 정보를 properties 파일로 저장해 줍니다. 저는 오라클의 scott 계정을 사용하기 위해 db.properties 파일을 다음과 같이 작성하였습니다.

    db.driver=oracle.jdbc.driver.OracleDriver
    db.url=jdbc:oracle:thin:@localhost:1521:xe
    db.username=scott
    db.password=tiger

     

    applicationContext.xml

    XML 설정 파일을 이용하는 방법입니다.  

     

    1. component-scan : 빈이 자동 등록 및 생성되도록 컴포넌트 스캔 대상 패키지를 지정합니다.
    2. properties 파일 등록 : DB 연동을 위한 정보를 저장해 놓은 properties 파일의 경로를 등록합니다.
    3. DataSource 등록 : BasicDataSource 빈을 등록하면서 properties 파일로부터 데이터를 가져와 프로퍼티로 설정해 줍니다. DataSource는 DB와 Connection을 맺고 일정량의 Connection을 미리 생성해서 저장소에 저장해 두었다가 필요시 제공하는 Connection Pooling 역할을 수행하는 객체입니다. 객체가 소멸될 때 close() 메소드를 호출하도록 destroy-method 속성을 설정합니다. 
    4. SqlSessionFactoryBean 등록 : SqlSessionFactoryBean을 이용해 SqlSessionFactory를 등록합니다. SqlSessionFactory는 내부적으로 SqlSession을 만들어내는 객체입니다. 프로퍼티로 DataSource를 주입하고, 사용할 Mapper 파일의 경로와, alias를 부여할 DTO 클래스의 경로를 설정해 줍니다. 
    5. SqlSessionTemplate 등록 : SqlSessionTemplate 빈을 등록하며 생성자를 통해 SqlSessionFactoryBean 빈을 주입받도록 합니다. SqlSessionTemplate은 SqlSession 인터페이스를 구현한 클래스로서 Connection을 생성하고 원하는 SQL을 전달하여 결과를 리턴받는 등의 핵심적인 역할을 수행하게 됩니다.
    <?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"
    	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-4.3.xsd">
    
    <!-- 1. component-scan -->
    <context:component-scan base-package="com.*"></context:component-scan>
    <!-- 2. properties 파일 등록 -->
    <context:property-placeholder location="classpath:config/db.properties"/>
    <!-- 3. DataSource 등록 -->
    <bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
    	<property name="driverClassName" value="${db.driver}"></property>
    	<property name="url" value="${db.url}"></property>
    	<property name="username" value="${db.username}"></property>
    	<property name="password" value="${db.password}"></property>
    </bean>
    <!-- 4. SqlSessionFactoryBean 등록 - mapper 지정, alias 지정 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" ref="dataSource"></property>
    	<property name="mapperLocations" value="classpath:mapper/*.xml"></property>
    	<property name="typeAliasesPackage" value="com.dto"></property>
    </bean>
    <!-- 5. SqlSessionTemplate 등록 -->
    <bean id="sqlSessionTemplate" class="org.mybatis.spring.SqlSessionTemplate">
    	<constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"></constructor-arg>
    </bean>
    
    </beans>

    아래와 같이 SqlSessionFactoryBean 등록시 Mapper와 DTO 경로를 각각 지정하여 list에 담아 주입할 수도 있습니다.

    <!-- 4. SqlSessionFactoryBean 등록 - mapper 지정, alias 지정 -->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    	<property name="dataSource" ref="dataSource"></property>
    	<property name="mapperLocations">
    		<list>
    			<value>classpath:mapper/MemberMapper.xml</value>
    		</list>
    	</property>
    	<property name="typeAliases">
    		<list>
    			<value>com.dto.MemberDTO</value>
    		</list>
    	</property>
    </bean>

     

    DTO 클래스

    MemberDTO.java 입니다. 자바에서는 클래스에 대한 alias 설정을 Configuration 설정 파일에서 했었지만, Spring에서는 클래스 상단부분에 @Alias로 지정할 수 있습니다. 

    @Alias("MemberDTO")
    public class MemberDTO {
    	int num;
    	String username;
    	String address;
    	
    	@Override
    	public String toString() {
    		return "MemberDTO [num=" + num + ", username=" + username + ", address=" + address + "]";
    	}
    	
        //Constructor, Getters and Setters
    }

     

    Mapper.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="MemberMapper">
    
    </mapper>

     

    이렇게 하면 MyBatis를 사용하기 위한 기본적인 환경설정이 완료됩니다. 이제 실제 DB에 데이터를 insert하고 select하는 등의 작업을 해 보도록 하겠습니다.

     

     

    실습

    TestMain.java

    멤버 한 명을 insert한 후 전체 멤버를 조회하고자 합니다.

    public class TestMain {
    	public static void main(String[] args) {
    		ApplicationContext ctx = new GenericXmlApplicationContext("classpath:config/applicationContext.xml");
    		MemberService service = ctx.getBean("memberService", MemberService.class);
    		//멤버 추가
    		int n = service.insert(new MemberDTO(10, "Amy", "Seoul"));
    		System.out.println(n+"개의 레코드 추가");
    		//전체 멤버 조회
    		List<MemberDTO> list = service.select();
    		for (MemberDTO dto : list) {
    			System.out.println(dto);
    		}
    	}
    }

     

    MemberService.java

    Service 클래스입니다. 클래스의 선언부에 @Service 어노테이션을 지정하여 컴포넌트 스캔 대상이 되도록 합니다. Service 클래스에서 사용할 DAO 클래스는 자동 주입이 되도록 합니다. 기존에 Spring Framework를 사용하지 않고 자바 코드만으로 MyBatis를 사용하던 것과 비교했을 때 Service 클래스의 코드가 상당히 간결해졌습니다. MyBatis-Spring 라이브러리를 사용하면 SqlSessionFactory를 직접 사용하여 SqlSession을 얻고 commit을 명시적으로 작성하거나 Session을 close하는 등의 작업이 필요 없습니다. DAO 클래스에서 사용할 SqlSessionTemplate은 Session의 closing을 포함한 라이프 사이클을 관리하며 자동 commit, 그리고 Spring 트랜잭션 설정시 필요하면 rollback까지 해주기 때문에, Service 클래스에서는 단순히 DAO 클래스의 메소드를 호출하기만 하면 됩니다.

    @Service
    public class MemberService {
    	@Autowired
    	private MemberDAO dao;
    	//멤버 추가
    	public int insert(MemberDTO dto) {
    		return dao.insert(dto);
    	}
    	//전체 멤버 조회
    	public List<MemberDTO> select() {
    		return dao.select();
    	}
    }

     

    MemberDAO.java

    클래스의 선언부에 @Repository 어노테이션을 지정하여 컴포넌트 스캔 대상이 되도록 합니다. DAO 클래스에서는 SqlSessionTemplate을 자동 주입받도록 합니다. SqlSessionTemplate은 SqlSession을 구현하고 SqlSession를 대체하는 역할을 합니다. 쓰레드에 안전(thread safe)하기 때문에 하나의 인스턴스가 모든 DAO에서 공유될 수 있습니다. 

    @Repository
    public class MemberDAO {
    	@Autowired
    	private SqlSessionTemplate session;
    	//멤버 추가
    	public int insert(MemberDTO dto) {
    		return session.insert("MemberMapper.insert", dto);
    	}
    	//전체 멤버 조회
    	public List<MemberDTO> select() {
    		return session.selectList("MemberMapper.select");
    	}
    }

     

    MemberMapper.xml

    DTO 클래스의 선언부에 어노테이션으로 지정해 주었던 alias를 사용하여 parameterType, resultType을 지정해 줍니다.

    <?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="MemberMapper">
    
    <insert id="insert" parameterType="MemberDTO">
    	insert into test
    		(num, username, address)
    	values
    		(#{num}, #{username}, #{address})
    </insert>
    
    <select id="select" resultType="MemberDTO">
    	select * from test
    </select>
    
    </mapper>

    insert한 멤버를 포함한 전체 멤버가 조회되는 것을 확인할 수 있습니다.

     

    이상으로 Spring에서 MyBatis를 사용하기 위한 기본적인 환경설정과 간단한 예제를 살펴보았습니다. 

     

     

    참고

     

     

    댓글