목차
- 통합 개요
- 통합 구현
- 환경 설정
- 실습 예제
- 마이바티스 플러스 통합 시 문제 해결
- 의존성 문제
- 구성 문제
- 매퍼 인터페이스 및 XML 파일 문제
- 엔티티 클래스 문제
- 데이터베이스 연결 문제
- SQL 문장 문제
- 스프링 컨테이너 문제
- 기타 문제
1. 통합 개요
마이바티스와 스프링 부트를 통합하는 핵심 원리는 다음과 같습니다:
- 마이바티스의 DataSource를 스프링 IoC 컨테이너가 생성하고 관리하도록 설정합니다. 이때 마이바티스 내장 데이터베이스 커넥션 풀 대신 Druid, C3P0 등의 외부 데이터베이스 커넥션 풀을 사용합니다.
- 마이바티스의 SqlSessionFactory를 스프링 IoC 컨테이너가 생성하고 관리하도록 설정합니다. 프로젝트 내의 MyBatisUtil 유틸리티 클래스 대신 spring-mybatis 통합 jar 패키지에 포함된 SqlSessionFactoryBean 클래스를 사용합니다.
- 마이바티스의 인터페이스 프록시 방식으로 생성된 구현체를 스프링 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&useSSL=true&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 또는 빌드 도구 캐시로 인한 문제일 수 있습니다. 캐시를 정리하고 프로젝트를 다시 빌드해보세요.
- 코드 오류: 코드에 논리 오류 또는 구문 오류가 존재할 수 있습니다.