스프링 부트와 마이바티스 통합 완벽 가이드

목차

  1. 통합 개요
  2. 통합 구현
    1. 환경 설정
    2. 실습 예제
  3. 마이바티스 플러스 통합 시 문제 해결
    1. 의존성 문제
    2. 구성 문제
    3. 매퍼 인터페이스 및 XML 파일 문제
    4. 엔티티 클래스 문제
    5. 데이터베이스 연결 문제
    6. SQL 문장 문제
    7. 스프링 컨테이너 문제
    8. 기타 문제

1. 통합 개요

마이바티스와 스프링 부트를 통합하는 핵심 원리는 다음과 같습니다:

  1. 마이바티스의 DataSource를 스프링 IoC 컨테이너가 생성하고 관리하도록 설정합니다. 이때 마이바티스 내장 데이터베이스 커넥션 풀 대신 Druid, C3P0 등의 외부 데이터베이스 커넥션 풀을 사용합니다.
  2. 마이바티스의 SqlSessionFactory를 스프링 IoC 컨테이너가 생성하고 관리하도록 설정합니다. 프로젝트 내의 MyBatisUtil 유틸리티 클래스 대신 spring-mybatis 통합 jar 패키지에 포함된 SqlSessionFactoryBean 클래스를 사용합니다.
  3. 마이바티스의 인터페이스 프록시 방식으로 생성된 구현체를 스프링 IoC 컨테이너가 생성하고 관리하도록 설정합니다.

마이바티스 프레임워크 개발 단계는 다음과 같습니다:

  • 매퍼 인터페이스 정의 및 메소드 작성
  • 매퍼 XML 매핑 파일 정의
  • 마이바티스 핵심 설정 파일 생성
  • SqlSession 객체 생성 및 해당 객체를 사용해 매퍼 인터페이스의 프록시 객체 생성 후 메소드 실행

스프링과 마이바티스 통합의 핵심은 마이바티스 개발에 사용되는 객체들을 스프링 컨테이너의 IoC로 생성하는 것입니다. 이를 통해 통합 목적을 달성할 수 있습니다. 개발 시에는 일반적으로 마이바티스가 내장한 데이터소스 대신 c3p0, dbcp 등 외부 데이터소스를 사용합니다. 본 예제에서는 알리바바의 드루이드 데이터소스를 사용합니다.

2. 통합 구현

2.1 환경 설정

필요한 의존성을 추가합니다:

<dependencies>
    <!--단위 테스트-->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <!--스프링 핵심 ioc-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.5.RELEASE</version>
    </dependency>
    <!--마이바티스 의존성-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>3.5.1</version>
    </dependency>
    <!--마이바티스와 스프링 통합 의존성-->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.1</version>
    </dependency>
    <!--mysql 드라이버-->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>5.1.9</version>
    </dependency>
    <!--알리바바의 데이터베이스 커넥션 풀-->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>druid</artifactId>
      <version>1.1.12</version>
    </dependency>
  </dependencies>

  <build>
    <!--src/main/java 디렉토리의 xml 파일을 출력 결과에 포함시키기 위함. classes 디렉토리로 출력-->
    <resources>
      <resource>
        <directory>src/main/java</directory><!--파일이 있는 디렉토리-->
        <includes><!--디렉토리의 .properties, .xml 파일을 모두 스캔-->
          <include>**/*.properties</include>
          <include>**/*.xml</include>
        </includes>
        <filtering>false</filtering>
      </resource>
    </resources>
    <jdk 버전 지정-->
    <plugins>
      <plugin>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.8</source>
          <target>1.8</target>
        </configuration>
      </plugin>
    </plugins>
  </build>

주의: resources 태그의 구성이 중요합니다. 여기서 오류가 발생하면 프로그램 실행 시 mapper.xml 파일을 찾지 못하는 오류가 발생할 수 있습니다.

2.2 실습 예제

본 예제에서는 학생 테이블에서 학생 정보를 조회하고 새로운 학생을 추가하는 기능을 구현합니다.

엔티티 클래스 User

public class User {
    private int userId;
    private String userName;
    private int cardNumber;
    private int classNumber;
    
    public User() {
    }
    
    public User(int userId, String userName, int cardNumber, int classNumber) {
        this.userId = userId;
        this.userName = userName;
        this.cardNumber = cardNumber;
        this.classNumber = classNumber;
    }
    
    // Getter 및 Setter 메소드
    public int getUserId() {
        return userId;
    }
    
    public void setUserId(int userId) {
        this.userId = userId;
    }
    
    public String getUserName() {
        return userName;
    }
    
    public void setUserName(String userName) {
        this.userName = userName;
    }
    
    public int getCardNumber() {
        return cardNumber;
    }
    
    public void setCardNumber(int cardNumber) {
        this.cardNumber = cardNumber;
    }
    
    public int getClassNumber() {
        return classNumber;
    }
    
    public void setClassNumber(int classNumber) {
        this.classNumber = classNumber;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "userId=" + userId +
                ", userName='" + userName + '\'' +
                ", cardNumber=" + cardNumber +
                ", classNumber=" + classNumber +
                '}';
    }
}

매퍼 인터페이스

public interface UserMapper {
    // 전체 조회
    List<User> getAllUsers();
    // 새로운 사용자 추가
    void addUser(User user);
}

매퍼 XML 매핑 파일

<?xml version="1.0" encoding="UTF-8" ?>

<mapper namespace="com.example.mapper.UserMapper">

    <!--전체 조회-->
    <select id="getAllUsers" resultType="User">
        select * from user
    </select>

    <!--새로운 사용자 추가-->
    <insert id="addUser" parameterType="User">
        insert into user (userid,username,cardnumber,classnumber)
        values (#{userId},#{userName},#{cardNumber},#{classNumber})
    </insert>
</mapper>

서비스 인터페이스

public interface IUserService {
    List<User> getAllUsers();
    void addUser(User user);
}

서비스 구현 클래스

public class UserServiceImpl implements IUserService {
    // 매퍼 속성
    private UserMapper userMapper;
    
    // setter 주입을 통해 매퍼 객체에 값 할당
    public void setUserMapper(UserMapper userMapper) {
        this.userMapper = userMapper;
    }
    
    @Override
    public List<User> getAllUsers() {
        return userMapper.getAllUsers();
    }

    @Override
    public void addUser(User user) {
        userMapper.addUser(user);
    }
}

마이바티스 핵심 설정 파일

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>
    <typeAliases>
        <!--
            패키지 이름을 지정하여 해당 패키지의 모든 클래스에 대해 별칭을 자동으로 설정합니다.
            별칭은 클래스명과 동일하며 대소문자를 구분하지 않습니다.
        -->
        <package name="com.example.entity" />
    </typeAliases>
    <!--매핑 설정 파일 로드-->
    <mappers>
        <mapper resource="com/example/mapper/userMapper.xml"></mapper>
    </mappers>
</configuration>

여기서는 데이터소스 객체를 스프링 컨테이너가 관리하도록 설정했으므로, 마이바티스 핵심 설정 파일에는 environments 태그가 필요 없습니다.

스프링 설정 파일

<?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 https://www.springframework.org/schema/context/spring-context.xsd">

    <!--데이터베이스 설정 파일 로드-->
    <context:property-placeholder location="classpath:db.properties"/>
    <!--데이터소스 선언-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!--setter 주입을 통해 데이터베이스 정보 할당. 드라이버 클래스는 지정할 필요 없음, 스프링이 url 자동 인식-->
        <!--
        <property name="url" value="jdbc:mysql://localhost:3306/test?characterEncoding=utf8&amp;useSSL=true&amp;serverTimezone=UTC"/>
        <property name="username" value="root"/>
        <property name="password" value="333"/>
        -->

        <!--db 설정 파일을 사용하여 데이터베이스 정보 읽기, el 표현식 형식-->
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
    </bean>

    <!--마이바티스에서 제공하는 SqlSessionFactoryBean 클래스 선언. 이 클래스 내부에서 SqlSessionFactory 생성-->
    <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--setter 주입 값 할당-->
        <!--setter 주입, 데이터베이스 커넥션 풀을 dataSource 속성에 주입-->
        <property name="dataSource" ref="dataSource" />
        <!--마이바티스 메인 설정 파일 위치
           configLocation 속성은 Resource 타입, 설정 파일 읽기
           값 할당은 value 사용, 파일 경로 지정 시 classpath: 사용
        -->
        <property name="configLocation" value="classpath:mybatis-config.xml" />
    </bean>

    <!--dao 객체 생성, SqlSession의 getMapper(UserMapper.class) 사용
        MapperScannerConfigurer: 내부적으로 getMapper()를 호출하여 각 dao 인터페이스의 프록시 객체 생성.
    -->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <!--SqlSessionFactory 객체 id 지정-->
        <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory" />
        <!--패키지 이름 지정, dao 인터페이스가 있는 패키지 이름.
            MapperScannerConfigurer는 이 패키지의 모든 인터페이스를 스캔하고 각 인터페이스에 대해
            getMapper() 메소드를 한 번씩 실행하여 각 인터페이스의 dao 객체를 얻습니다.
            생성된 dao 객체는 스프링 컨테이너에 저장됩니다. dao 객체의 기본 이름은 인터페이스 이름의 첫 글자 소문자
        -->
        <property name="basePackage" value="com.example.mapper"/>
    </bean>

    <!--서비스 선언-->
    <bean id="userServiceImpl" class="com.example.service.impl.UserServiceImpl">
        <property name="userMapper" ref="userMapper"/>
    </bean>
</beans>

데이터베이스 설정 파일

url = jdbc:mysql://localhost:3306/YourDatabase?characterEncoding=utf8&useSSL=true&serverTimezone=UTC
username = YourUsername
password = YourPassword

3. 마이바티스 플러스 통합 시 문제 해결

1. 의존성 문제

  • 의존성 제대로 추가되지 않음: pom.xml 또는 build.gradle에 마이바티스 플러스 의존성이 제대로 추가되었는지 확인하세요.
  • 버전 호환성 문제: 사용 중인 마이바티스 플러스 버전과 스프링 부트 버전이 호환되지 않을 수 있습니다. 호환되는 버전으로 업데이트하세요.

2. 구성 문제

  • 구성 파일 누락 또는 오류: application.properties 또는 application.yml에 올바른 마이바티스 플러스 구성이 있는지 확인하세요.
  • 매퍼 스캔 경로 오류: @MapperScan 어노테이션이 지정한 경로와 매퍼 인터페이스가 있는 패키지가 일치하지 않을 수 있습니다.

3. 매퍼 인터페이스 및 XML 파일 문제

  • 매퍼 인터페이스 어노테이션 누락: 매퍼 인터페이스에 @Mapper 또는 @Repository 어노테이션이 없거나 잘못 사용되었습니다.
  • XML 파일 위치 오류: XML 파일 위치가 구성 파일에서 지정한 위치와 일치하지 않습니다.
  • XML 파일 네임스페이스 오류: XML 파일의 네임스페이스와 매퍼 인터페이스의 전체 경로가 일치하지 않습니다.

4. 엔티티 클래스 문제

  • 엔티티 클래스 어노테이션 누락 또는 오류: @TableName, @TableId 등 어노테이션이 누락되었거나 잘못 사용되었습니다.
  • 필드 타입 불일치: 데이터베이스 필드 타입과 엔티티 클래스 필드 타입이 일치하지 않습니다.

5. 데이터베이스 연결 문제

  • 데이터베이스 URL 오류: 데이터베이스 URL, 사용자 이름, 비밀번호 등 구성이 잘못되었습니다.
  • 드라이버 누락: 데이터베이스 드라이버 의존성이 추가되지 않았습니다.

6. SQL 문장 문제

  • SQL 문장 오류: XML 파일의 SQL 문장에 구문 오류 또는 논리 오류가 있습니다.
  • 플레이스홀더 오류: SQL 문장에 잘못된 플레이스홀더가 사용되었습니다.

7. 스프링 컨테이너 문제

  • 빈 생성 실패: 구성 오류 또는 의존성 문제로 인해 스프링 컨테이너가 필요한 빈을 생성할 수 없습니다.
  • 순환 의존성: 빈 간에 순환 의존성이 존재하여 스프링 컨테이너를 초기화할 수 없습니다.

8. 기타 문제

  • IDE 또는 빌드 도구 문제: IDE 또는 빌드 도구 캐시로 인한 문제일 수 있습니다. 캐시를 정리하고 프로젝트를 다시 빌드해보세요.
  • 코드 오류: 코드에 논리 오류 또는 구문 오류가 존재할 수 있습니다.

태그: 스프링 부트 마이바티스 자바 데이터베이스 ORM

6월 12일 16:34에 게시됨