2024. 7. 6. 23:27ㆍBE/Spring
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/*.xml
는mapper
라는 이름의 폴더 안에 있는 모든.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.properties
와 mybatis-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 |