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

    Copyright ${license.git.copyrightYears} the original author or authors.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

-->
<document xmlns="http://maven.apache.org/XDOC/2.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">

  <properties>
    <title>마이바티스 스프링 연동모듈 | SqlSession 사용</title>
    <author email="hpresnall@gmail.com">Hunter Presnall</author>
    <author email="eduardo.macarron@gmail.com">Eduardo Macarron</author>
    <author email="fromm0@gmail.com">이동국(한국어 번역)</author>
  </properties>

  <body>
    <section name="SqlSession 사용">
      <p>마이바티스에서는 <code>SqlSession</code>를 생성하기 위해 <code>SqlSessionFactory</code>를 사용한다. 
      세션을 한번 생성하면 매핑구문을 실행하거나 커밋 또는 롤백을 하기 위해 세션을 사용할수 있다. 
      마지막으로 더 이상 필요하지 않은 상태가 되면 세션을 닫는다. 
      마이바티스 스프링 연동모듈을 사용하면 <code>SqlSessionFactory</code>를 직접 사용할 필요가 없다.
      왜냐하면, 스프링 트랜잭션 설정에 따라 자동으로 커밋 혹은 롤백을 수행하고 닫혀지는, 쓰레드에 안전한 <code>SqlSession</code> 개체가 스프링 빈에 주입될 수 있기 때문이다.</p>

    <subsection name="SqlSessionTemplate">
      <p><code>SqlSessionTemplate</code>은 마이바티스 스프링 연동모듈의 핵심이다. 
      <code>SqlSessionTemplate</code>은 <code>SqlSession</code>을 구현하고 코드에서 <code>SqlSession</code>를 대체하는 역할을 한다. 
      <code>SqlSessionTemplate</code> 은 쓰레드에 안전하고 여러개의 DAO나 매퍼에서 공유할수 있다. </p>

      <p><code>getMapper()</code>에 의해 리턴된 매퍼가 가진 메서드를 포함해서 SQL을 처리하는 마이바티스 메서드를 호출할때
      <code>SqlSessionTemplate</code>은 <code>SqlSession</code>이 현재의 스프링 트랜잭션에서 사용될수 있도록 보장한다.
      추가적으로 <code>SqlSessionTemplate</code>은 필요한 시점에 세션을 닫고, 커밋하거나 롤백하는 것을 포함한 세션의 생명주기를 관리한다.
      또한 마이바티스 예외를 스프링의 <code>DataAccessException</code>로 변환하는 작업또한 처리한다. </p>

      <p><code>SqlSessionTemplate</code>은 마이바티스의 디폴트 구현체인 <code>DefaultSqlSession</code> 대신 <strong>항상</strong> 사용된다.
      왜냐하면 템플릿은 스프링 트랜잭션의 일부처럼 사용될 수 있고 여러개 주입된 매퍼 클래스에 의해 사용되도록 쓰레드에 안전하다.
      동일한 애플리케이션에서 두개의 클래스간의 전환은 데이터 무결성 이슈를 야기할수 있다. </p>

      <p><code>SqlSessionTemplate</code>은 생성자 인자로 <code>SqlSessionFactory</code>를 사용해서 생성될 수 있다. </p>
        <source><![CDATA[<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>]]></source>

      <source><![CDATA[
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
  return new SqlSessionTemplate(sqlSessionFactory());
}]]></source>

      <p>이 빈은 DAO빈에 직접 주입될 수 있다. 다음처럼 빈 설정에서 <code>SqlSession</code> 프로퍼티를 설정하면 된다. </p>
        <source><![CDATA[public class UserDaoImpl implements UserDao {

  private SqlSession sqlSession;

  public void setSqlSession(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
  }

  public User getUser(String userId) {
    return sqlSession.selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}]]></source>
      <p>그리고 다음처럼 <code>SqlSessionTemplate</code> 를 주입하자. </p>      
      <source><![CDATA[<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSession" ref="sqlSession" />
</bean>]]></source>
      
      <p><code>SqlSessionTemplate</code>은 인자로 <code>ExecutorType</code>를 가지는 생성자를 가지고 있다. 
      이 인자는 예를들면 스프링 설정 XML을 다음처럼 설정해서 배치형태의 <code>SqlSession</code>를 만들수도 있다. </p>
        <source><![CDATA[<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
  <constructor-arg index="0" ref="sqlSessionFactory" />
  <constructor-arg index="1" value="BATCH" />
</bean>]]></source>

      <source><![CDATA[
@Bean
public SqlSessionTemplate sqlSession() throws Exception {
  return new SqlSessionTemplate(sqlSessionFactory(), ExecutorType.BATCH);
}]]></source>

      <p>DAO의 코드를 다음처럼 작성했다면 모든 구문은 배치형태로 실행이 될 것이다. </p>
        <source><![CDATA[
public void insertUsers(List<User> users) {
  for (User user : users) {
    sqlSession.insert("org.mybatis.spring.sample.mapper.UserMapper.insertUser", user);
  }
}]]></source>
  
      <p>이러한 설정형태는 <code>SqlSessionFactory</code>의 디폴트 형태가 아닌 다른형태로 메서드를 실행해야 할때만 사용할 필요가 있다. </p>

      <p>이러한 형태에 대해 굳이 경로를 하자면 메서드를 호출할때 ExecutorType이 다르면 이미 시작된 트랜잭션을 사용하지 <strong>못할</strong>것이다.      
       다른 실행자(executor) 타입을 사용할때는 <code>SqlSessionTemplate</code>의 메서드를 구분된 트랜잭션(PROPAGATION_REQUIRES_NEW를 사용하는)이나 트랜잭션 외부에서 호출하는지 확실히해야 한다. </p>
    </subsection>

    <subsection name="SqlSessionDaoSupport">
      <p><code>SqlSessionDaoSupport</code>는 <code>SqlSession</code>을 제공하는 추상클래스이다.
      <code>getSqlSession()</code>메서드를 호출해서 다음처럼 SQL을 처리하는 마이바티스 메서드를 호출하기 위해 사용할 <code>SqlSessionTemplate</code>을 얻을 수 있다. </p>
        <source><![CDATA[public class UserDaoImpl extends SqlSessionDaoSupport implements UserDao {
  public User getUser(String userId) {
    return getSqlSession().selectOne("org.mybatis.spring.sample.mapper.UserMapper.getUser", userId);
  }
}]]></source>
      <p>대개 <code>MapperFactoryBean</code>은 추가적인 코드가 필요없기 때문에 이 클래스를 선호한다. 
      하지만 DAO에서 마이바티스가 필요하지 않고 구현된 클래스가 필요하지 않을때만 유용하다. </p>

      <p><code>SqlSessionDaoSupport</code>는 <code>sqlSessionFactory</code> 와 <code>sqlSessionTemplate</code> 프로퍼티를 셋팅할 필요가 있다. 
      두개의 프로퍼티를 모두 셋팅하면 <code>sqlSessionFactory</code>는 무시된다. </p>

      <p><code>SqlSessionDaoSupport</code>의 하위클래스인 <code>UserDaoImpl</code>가 있다고 하면 스프링에서는 다음처럼 설정될 수 있다. </p>
      <source><![CDATA[<bean id="userDao" class="org.mybatis.spring.sample.dao.UserDaoImpl">
  <property name="sqlSessionFactory" ref="sqlSessionFactory" />
</bean>]]></source>
      </subsection>
    </section>
  </body>
</document>
