[spring] mybatis/mysql/spring 연동

이혜윤·2024년 4월 9일

spring

목록 보기
1/3

https://mybatis.org/mybatis-3/ko/getting-started.html#%EB%A7%A4%ED%95%91%EB%90%9C-sql-%EA%B5%AC%EB%AC%B8-%EC%82%B4%ED%8E%B4%EB%B3%B4%EA%B8%B0

1. 개념

1.1 정의

SQL문과 자바 객체를 매핑하는 오픈 소스 프레임워크 ( Spring과는 종속성을 가지고 있지 않은 독립적인 프레임워크)

SQL 쿼리를 처리하고 자바 객체와 데이터베이스 간의 매핑을 DAO(Data Access Object) - JDBC 사이에서 담당하여 처리

JDBC 만을 사용했을 때 코드 작성 및 관리에 대한 불편함 등을 해소

1.2 주요 기능

ApplicationO/R MapperJDBC인터페이스JDBC구현체Persistance Layer

: SeviceDAOMybatis3JDBC&DataSource(DB 연결에 대한 설정 정보)JDBC DriverDB

  • SQL문과 자바 코드를 분리 : SQL 문을 XML파일이나 어노테이션에 작성하여 이를 분리.
  • 동적 SQL 지원 : 조건에 따라 다양한 sQL문 실행
  • 결과 매핑 지원: 복잡한 SQL 쿼리 결과를 자바 객체에 쉽게 매핑

1.3 구성 요소

SQL 쿼리 실행이나 트랜잭션 관리를 위한 메소드를 가진 SqlSession이라는 인터페이스를 중점으로 데이터베이스와 인터렉션을 수행.

아래의 주요 객체들을 통해 어플리케이션은 데이터베이스와 직접적으로 인터렉션을 가질 필요 없이, 필요한 데이터를 객체 형태로 쉽게 활용

sqlSessionFactoryBuilder

  • sqlSessionFactory 인스턴스를 생성하는 데 사용되는 빌더 클래스
  • XML 설정 파일에서 alis, DB연결환경, Mapper 리소스 파일 설정 정보를 읽어오고 sqlSessionFactory 객체를 생성

sqlSessionFactory

  • sqlSession 객체를 생성하는 팩토리 클래스.
  • 런타임 도중 CRUD 처리 요청에 따라 sqlSession 객체 생성

sqlSession

  • SQL 실행이나 트랜잭션 관리를 위한 메소드를 가진 인터페이스
  • sql매핑 파일에서 정의한 SQL 문을 실행하는 역할

sqlSessionFactoryBean

mybatis와 spring을 연결하는 데 중요한 역할을 하는 Bean.

XML 설정 파일을 통해 mybatis 의 sqlSessionFactory 를 spring 컨테이너에 등록할 수 있다.

sqlSessionTemplate

mybatis-spring의 핵심 구현체

sqlSession을 구현하고 코드에서 sqlSession을 대체하여 사용

멀티쓰레드 상황에도 안정적(thread-safe)이며, 필요한 시점에 세션을 닫고, 커밋하거나 롤백하는 역할

같은 트랜잭션에서 여러 개의 동일한 sqlSession을 공유할 수 있도록 한다.

1.4 Mybatis-spring

mybatis와 srping 프레임워크를 통합하는 라이브러리.

mybatis와 spring 프레임워크 둘을 연결하려면 스프링의 트랜잭션 관리와 mybatis mapper의 bean 등록 등 추가설정을 필요로 한다. 이로 인해 설정 및 코드가 복잡해지고 유지 보수가 어려워지므로 이러한 일련의 통합과정을 mybatis-spring 라이브러리를 통해 간소화할 수 있다.

  • Mybatis 와 spring 프레임워크의 통합 지원: Mybatis를 사용하여 SQL문을 작성하고 실행하는 동안 spring 기능 활용 가능
  • 스프링 프레임워크의 트랜잭션 관리 지원: 스프링 프레임워크의 트랜잭션 관리 기능을 이용해 mybatis 를 사용한 쿼리를 안정적으로 실행 및 관리
  • mybatis mapper 인터페이스의 스프링 bean 등록 지원: mybatis mapper 인터페이스를 스프링의 bean으로 등록해 사용할 수 있게 해준다.
  • sqlSessionTemplate 지원: sqlSession을 대체하는 구현 객체로 스프링과 mybatis 사이의 통합을 완료하여 SQL 수행 및 스프링 트랜잭션을 정상적으로 사용할 수 있도록 보장

2. 구현

2.1 batis

2.1.1 pom.xml

<dependencies>
	<dependency>
		<groupId>com.mysql</groupId>
		<artifactId>mysql-connector-j</artifactId>
		<version>8.0.33</version>
	</dependency>
	<dependency>
	    <groupId>org.mybatis</groupId>
	    <artifactId>mybatis</artifactId>
	    <version>3.5.15</version>
	</dependency>
  </dependencies>

2) mybatis-config.xml

src 폴더와 같은 소속 위치에 sourceFolder 생성

<?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="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
      </dataSource>
    </environment>
  </environments>
  <mappers>
    <mapper resource="org/mybatis/example/BlogMapper.xml"/>
  </mappers>
</configuration>

위의 ${변수} 값은 아래와 같이 수정

  <environments default="development">
    <environment id="development">
      <transactionManager type="JDBC"/>
      <dataSource type="POOLED">
        <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306/my_board?serverTimeZone=UTC"/>
        <property name="username" value="mysql사용자이름"/>
        <property name="password" value="mysql사용자비밀번호"/>
      </dataSource>
    </environment>
  </environments>

2.1.2 Factory build



import java.io.IOException;
import java.io.InputStream;

import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

public class MyAppSqlConfig {
	
	// 공장 세워서 계속 불러다 쓸거야!
	
	private static SqlSessionFactory factory;
	
	static {
		// 자원의 위치를 기록.
		// 공장을 세워야 하는데,,,설정 파일(=자원) 위치
		String resource = "config/mybatis-config.xml";
		try {
			InputStream inputStream = Resources.getResourceAsStream(resource);
			factory = new SqlSessionFactoryBuilder().build(inputStream);
			System.out.println("공장건설완료");
		} catch (IOException e) {
			System.out.println("공장건설실패");
			e.printStackTrace();
		}
	}
	
	public static SqlSessionFactory getFactory() {
		return factory;
	}

}

2.1.3 mapper 설정

resources 폴더 내 mappers 폴더/패키지 생성

<?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.model.dao.BoardDao">
  <select id="selectAll" resultType="com.model.dto.Board">
    SELECT * FROM Board;
  </select>
</mapper>

mybatis-config.xml 에 내용 추가→ typeAliases, mappers

<?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>

	<typeAliases>
		<typeAlias type="com.board.model.dto.Board"
			alias="Board" />
	</typeAliases>


	<environments default="development">
		<environment id="development">
			<transactionManager type="JDBC" />
			<dataSource type="POOLED">
				<property name="driver" value="com.mysql.cj.jdbc.Driver" />
				<property name="url"
					value="jdbc:mysql://localhost:3306/my_board?serverTimeZone=UTC" />
				<property name="username" value="사용자ID" />
				<property name="password" value="사용자PW" />
			</dataSource>
		</environment>
	</environments>

	<mappers>
		<mapper resource="mappers/boardMapper.xml" />
	</mappers>

</configuration>

2.1.4 resultMap 생성

boardMapper.xml에 내용 추가, resultType 변경

<?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.board.model.dao.BoardDao">
	<resultMap type="Board" id="boardMap">
		<result column="id" property="id"/>
		<result column="writer" property="writer"/>
		<result column="title" property="title"/>
		<result column="content" property="content"/>
		<result column="view_cnt" property="viewCnt"/>
		<result column="reg_date" property="regDate"/>
	</resultMap>


   <select id="selectAll" resultType="boardMap">
    SELECT * FROM Board;
  </select>
  
	  <select id="selectOne" resultMap="boardMap" parameterType="int">
	  	SELECT * FROM board
	  	WHERE id = #{id};
	  </select>
</mapper>
  • property는 필드명이 아닌 getter!
  • 이때 column명과 property명이 같은 것은 생략가능 ex. id~content 까지는 다 생략해도 결과가 같다.

2.2 mybatis-spring

2.2.1 root-context.xml vs applicationContext.xml

WEB-INF/spring/root-context.xml

1) 어노테이션으로 설정한 model 패키지 하위 클래스를 빈으로 등록하기 위해 컴포넌트 스캔 범위 지정

<context:component-scan
		base-package="com.model"></context:component-scan>

2) 데이터베이스 연결을 위한 dataSource를 등록
이터베이스 연결을 위한 드라이버 클래스명, url, 사용자 이름, 비밀번호를 설정

	<bean id="dataSource"
		class="org.springframework.jdbc.datasource.DriverManagerDataSource">
		<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC"></property>
		<property name="username" value="mysql사용자ID"></property>
		<property name="password" value="mysql사용자PW"></property>
	</bean>

3-1) MyBatis를 사용하기 위한 sqlSessionFactory를 등록한다. sqlSessionFactory Bean 클래스를 사용해 Bean 등록을 진행
데이터베이스 연결을 위한 dataSource를 설정

	<bean id="sqlSessionFacotry"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		
		<!-- ... -->
	</bean>

3-2) mybatis 설정 파일 (보통 mybatis-config.xml) or 매퍼 xml 파일들을 추가로 지정

	<bean id="sqlSessionFacotry"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		
		<!-- 
		mapper xml 파일의 경로를 지정(ant형식) 
		-->
		**<property name="mapperLocations" value="classpath*:mappers/**/*.xml" />**
		
		<!-- 
		mapper에서 사용할 DTO들의 기본 패키지를 등록
		Mapper.xml에서 DTO의 클래스 명을 쓸 수 있다.
		이 때, 기본적으로 풀 패키지명을 써야한다.
		Class.forNmae("풀패키지명") => 패키지를 생략해주는 기능
		 -->
		 
		**<property name="typeAliasesPackage" value="com.model.dto"></property>
	</bea**

4) mybatis에서 제공하는 scan태그를 통해 repository interface들의 위치를 지정

<mybatis:scan base-package="com.model.dao" />

5) 필요한 경우, 트랜잭션 매니저를 Bean으로 등록 (id는 언제나 고정)

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<constructor-arg ref="dataSource"></constructor-arg>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

6-1) MyBatis Mapper 인터페이스를 스프링 Bean으로 등록하여 마무리

<mybatis:scan base-package="com.model.dao" />

6-2) 6-1 방식 대신 아래와 같이 sqlSessionTemplate을 Bean으로 등록하여 통합을 완료할수도

<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
	<constructor-arg ref="sqlSessionFactoryBean"></constructor-arg>
</bean>
@Autowired
private SqlSessionTemplate sqlSession;

src/main/resources/applicationContext.xml

1) mybatis bean 생성 (공식 홈페이지 참고)

<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"
	xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring http://mybatis.org/schema/mybatis-spring-1.2.xsd
		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
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">

2) dataSource 명시

<bean id="dataSource"
		class="org.apache.commons.dbcp2.BasicDataSource">
		<property name="driverClassName"
			value="com.mysql.cj.jdbc.Driver"></property>
		<property name="url"
			value="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC"></property>
		<property name="username" value="사용자ID"></property>
		<property name="password" value="사용자PW"></property>
	</bean>

3) MyBatis를 사용하기 위한 sqlSessionFactory를 등록

  • mapper xml 파일의 경로를 ant 표현식의 형태로 사용
  • mapper에서 사용할 DTO들의 기본 패키지를 등록
	<bean id="sqlSessionFactory"
		class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="dataSource" ref="dataSource" />
		<property name="mapperLocations"
			value="classpath*:mappers/**/*.xml" />
		<property name="typeAliasesPackage"
			value="com.model.dto"></property>
	</bean>

4) mybatis에서 제공하는 scan 태그를 통해 dao interface들의 위치를 지정

<mybatis-spring:scan base-package="com.model.dao" />

</beans>

2.2.2 mapper.xml

예시 ) CarDao 형식에 맞는 CarMapper.xml 생성



import java.util.List;

import com.model.dto.Car;

public interface CarDao {

	//자동차 등록
	int insert(Car car);
	
	//차량번호로 검색
	Car searchByVin(String vin);
	
	//자동차 목록
	List<Car> selectAll();
	
	//자동차 목록별로 검색
	List<Car> searchByModelName(String modelName);
}
<?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="com.model.dao.CarDao"> 


	<insert id="insert" parameterType="Car">
		INSERT INTO car
		VALUES(#{vin}, #{modelName}, #{color}, #{mileage}, #{img})
	</insert> 

	<select id="searchByVin" parameterType="String" resultType="Car">
		SELECT *
		FROM car WHERE vin = #{vin}
	</select> 


	<select id="searchByModelName" parameterType="String" resultType="Car">
		SELECT *
		FROM car WHERE modelName LIKE
		CONCAT('%',#{modelName},'%')
	</select> 

	
	<select id="selectAll" resultType="Car">
		SELECT * FROM car
	</select> 
</mapper> 

테스트 코드



import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.model.dao.CarDao;
import com.model.dto.Car;

public class CarTest {
	public static void main(String[] args) {
		ApplicationContext context = new GenericXmlApplicationContext("applicationContext.xml");

		CarDao carDao = context.getBean(CarDao.class);

		Car newCar = new Car("VIN123456789", "테스트 모델", "검정", 1000, "test.jpg", "test.jpg");
		int insertCount = carDao.insert(newCar);
		System.out.println(insertCount + "개의 자동차 정보가 등록되었습니다.");
		
		  // 모든 자동차 정보 조회
        List<Car> cars = carDao.selectAll();
        for (Car car : cars) {
            System.out.println(car);
        }

        // 특정 VIN으로 자동차 정보 조회
        Car car = carDao.searchByVin("VIN123456789");
        if (car != null) {
            System.out.println("조회된 자동차 정보: " + car);
        } else {
            System.out.println("해당 VIN의 자동차 정보가 없습니다.");
        }

	}
}

mapper.xml 작성 시 주의점

1) insert 메서드 자체는 int형 반환타입이지만, mapper.xml에서**<insert>** 태그의 경우는 resultType을 적지않는다. MyBatis에서 <insert>, <update>, <delete> 태그에 resultType을 명시하지 않는다.

2) 반환형이 List 이더라도 generic 해당 형태로만 명시

ex. List<Car> 반환형 메서드 → mybatis 태그 내에서는 resultType =”Car” 로 표시

3) AUTO_INCREMENT 필드는 insert 태그 내에서 생략

profile
구르미 누나

0개의 댓글