[Spring] MyBatis-Spring module

2024. 7. 6. 23:27BE/Spring

 

 

 

mybatis-spring

Getting Started This chapter will show you in a few steps how to install and setup MyBatis-Spring and how to build a simple transactional application. Installation To use the MyBatis-Spring module, you just need to include the mybatis-spring-3.0.3.jar file

mybatis.org

 


1. 설치

 

MyBatis-Spring module을 사용하기 위해서는 mybatis-spring-3.0.3.jar 파일과 그 외 dependencies를 classpath에 추가해야 한다.

 

단, Maven을 사용하는 경우 pom.xml에 아래 코드를 추가하면 된다.

 

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

MyBatis-Spring module을 사용하기 위해서는 Spring application context에 두 가지를 설정해야 한다.

 


2. 설정

 

SqlSessionFactory와 최소 하나 이상의 mapper interface가 정의되어야 한다.

 

거기에 mapper interface에서 SQL문을 별도의 XXXmapper.xml로 분리한다면 총 3개의 파일이 필요하다.

 


가. root-servlet.xml

 

MyBatis-Spring에서는 SqlSessionFactory를 생성하기 위해서 SqlSessionFactoryBean를 사용한다.

<!-- root-context.xml -->
<bean id="sqlSessionFactoryBean" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource"/>
    <property name="typeAliasesPackage" value="com.company.*.model"/>
    <property name="mapperLocations" value="classpath:mapper/*.xml"/>
</bean>
  • <property name="dataSource" ref="dataSource"/>
    : SqlSessionFactory을 생성하기 위해서는 DataSource가 있어야 한다.

  • <property name="typeAliasesPackage" value="com.company.*.model"/>
    : com.company.*.model 패키지 아래의 모든 모델 클래스는 전체 클래스 이름 대신 간단한 별칭으로 참조된다.

  • <property name="mapperLocations" value="classpath:mapper/*.xml"/>
    : MyBatis의 SQL 매핑 파일들이 위치한 경로를 지정하는 속성.
    : classpath:mapper/*.xmlmapper라는 이름의 폴더 안에 있는 모든 .xml 파일을 매핑 파일로 사용하겠다는 의미.

 

<!-- root-context.xml -->
<mybatis-spring:scan base-package="com.company.*.model.mapper" annotation="org.apache.ibatis.annotations.Mapper" />

정의된 mapper interface가 있다고 가정하면, 이 인터페이스는 등록되어야 한다.

 

또는 @Configuration 애너테이션을 활용해도 된다.

 

@Configuration
@MapperScan(basePackages = "com.company.*.model.mapper")
public class MyBatisConfig {
  @Bean
  public SqlSessionFactory sqlSessionFactory() throws Exception {
    SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
    factoryBean.setDataSource(dataSource());
    factoryBean.setTypeAliasesPackage("com.company.*.model");
    factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*.xml"));
    return factoryBean.getObject();
  }
}

나. mapper interface

@Mapper
public interface BoardMapper {

    void writeArticle(BoardDto boardDto) throws SQLException;

    void registerFile(BoardDto boardDto) throws Exception;

    List<BoardDto> listArticle(Map<String, Object> param) throws SQLException;

    int getTotalArticleCount(Map<String, Object> param) throws SQLException;

    BoardDto getArticle(int articleNo) throws SQLException;

    void updateHit(int articleNo) throws SQLException;

    void modifyArticle(BoardDto boardDto) throws SQLException;

    void deleteFile(int articleNo) throws Exception;

    void deleteArticle(int articleNo) throws SQLException;

    List<FileInfoDto> fileInfoList(int articleNo) throws Exception;

}

이때 Mapper는 반드시 인터페이스여야 한다.


다. XXXmapper.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="com.company.board.model.mapper.BoardMapper">

    <resultMap type="boardDto" id="article">
        <result column="article_no" property="articleNo"/>
        <result column="user_id" property="userId"/>
        <result column="user_name" property="userName"/>
        <result column="subject" property="subject"/>
        <result column="content" property="content"/>
        <result column="hit" property="hit"/>
        <result column="register_time" property="registerTime"/>
    </resultMap>

    <resultMap type="boardDto" id="viewArticle" extends="article">
        <collection property="fileInfos" column="article_no" javaType="list" ofType="fileInfoDto" select="fileInfoList"/>
    </resultMap>

    <resultMap type="fileInfoDto" id="file">
        <result column="save_folder" property="saveFolder"/>
        <result column="original_file" property="originalFile"/>
        <result column="save_file" property="saveFile"/>
    </resultMap>

    <insert id="writeArticle" parameterType="boardDto">
        insert into board (user_id, subject, content, hit, register_time)
        values (#{userId}, #{subject}, #{content}, 0, now())
        <selectKey resultType="int" keyProperty="articleNo" order="AFTER">
            select last_insert_id()
        </selectKey>
    </insert>

    <insert id="registerFile" parameterType="boardDto">
        insert into file_info (article_no, save_folder, original_file, save_file)
        values
        <foreach collection="fileInfos" item="fileinfo" separator=" , ">
            (#{articleNo}, #{fileinfo.saveFolder}, #{fileinfo.originalFile}, #{fileinfo.saveFile})
        </foreach>
    </insert>

    <sql id="search">
        <if test="word != null and word != ''">
            <if test="key == 'subject'">
                and subject like concat('%', #{word}, '%')
            </if>
            <if test="key != 'subject'">
                and ${key} = #{word}
            </if>
        </if>
    </sql>

    <select id="listArticle" parameterType="map" resultMap="article">
        select b.article_no, b.user_id, b.subject, b.content, b.hit, b.register_time, m.user_name
        from board b, members m 
        where b.user_id = m.user_id
        <include refid="search"></include>
        order by b.article_no desc
        limit #{start}, #{listsize}
    </select>

    <select id="getTotalArticleCount" parameterType="map" resultType="int">
        select count(article_no)
        from board
        <where>
            <include refid="search"></include>
        </where>
    </select>

    <select id="getArticle" parameterType="int" resultMap="viewArticle">
        select b.article_no, b.user_id, b.subject, b.content, b.hit, b.register_time, m.user_name 
        from board b, members m
        where b.user_id = m.user_id
        and b.article_no = #{articleNo}
    </select>

    <select id="fileInfoList" resultMap="file">
        select save_folder, original_file, save_file
        from file_info
        where article_no = #{articleNo}
    </select>

    <update id="updateHit" parameterType="int">
        update board
        set hit = hit + 1
        where article_no = #{articleNo}
    </update>

    <update id="modifyArticle" parameterType="boardDto">
        update board
        set subject = #{subject}, content = #{content}
        where article_no = #{articleNo}
    </update>

    <delete id="deleteFile" parameterType="int">
        delete from file_info
        where article_no = #{articleNo}
    </delete>

    <delete id="deleteArticle" parameterType="int">
        delete from board
        where article_no = #{articleNo}
    </delete>

</mapper>

3. 사용

@Service
public class BoardServiceImpl implements BoardService {

    private BoardMapper boardMapper;

    public BoardServiceImpl(BoardMapper boardMapper) {
        super();
        this.boardMapper = boardMapper;
    }

    @Override
    @Transactional
    public void writeArticle(BoardDto boardDto) throws Exception {
        boardMapper.writeArticle(boardDto);
        List<FileInfoDto> fileInfos = boardDto.getFileInfos();
        if (fileInfos != null && !fileInfos.isEmpty()) {
            boardMapper.registerFile(boardDto);
        }
    }
    ...

Service에서 mapper의 method를 호출하면 된다.

 

 


4. @Transactional

@Service
public class BoardServiceImpl implements BoardService {

    private BoardMapper boardMapper;

    public BoardServiceImpl(BoardMapper boardMapper) {
        super();
        this.boardMapper = boardMapper;
    }

    @Override
    @Transactional
    public void writeArticle(BoardDto boardDto) throws Exception {
        boardMapper.writeArticle(boardDto);
        List<FileInfoDto> fileInfos = boardDto.getFileInfos();
        if (fileInfos != null && !fileInfos.isEmpty()) {
            boardMapper.registerFile(boardDto);
        }
    }
    ...

Mabatis-Spring의 autocommit의 기본값은 true다.

 

boardMapper.writeArticle(boardDto);boardMapper.registerFile(boardDto); 모두 성공해야 commit되고 하나라도 실패하면 rollback되도록 하기 위해서 @Transactional 이 필요하다.

 

<!-- root-context.xml -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource" />
</bean>

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

@Transactional 사용 시 transactionManager가 필요하다.

 


 

dbinfo.propertiesmybatis-config.xml이 더 이상 필요 없다.

 

'BE > Spring' 카테고리의 다른 글

[Spring] Rest API  (0) 2024.07.06
[Spring] 비동기 통신  (0) 2024.07.06
[MyBatis] 동적 SQL  (0) 2024.07.06
[MyBatis] MyBatis란?  (0) 2024.07.06
[Spring] Connection Pool  (0) 2024.07.06