자바 API

이제 마이바티스를 설정하는 방법과 매핑을 만드는 방법을 알게 되었다. 이미 충분히 잘 사용할 준비가 된 셈이다. 마이바티스 자바 API 는 당신의 노력에 대한 보상을 얻게 할 것이다. JDBC 와 비교해보면 마이바티스는 코드를 굉장히 단순하게 만들고 깔끔하게 만든다. 이해하기 쉬워서 유지보수도 편하게 해준다. 마이바티스 3은 SQL Map을 사용하는 많은 수의 개선 내용을 소개했다.

디렉터리 구조

자바 API 를 살펴보기 전에 디렉터리 구조에 대해 전반적으로 이해하는 것이 중요하다. 마이바티스는 매우 유연하고 파일을 사용해서 어떤 것도 할 수 있다. 하지만 프레임워크이기 때문에 선호하는 방법이 있다.

전형적인 애플리케이션 디렉터리 구조를 살펴보자.

/my_application
  /bin
  /devlib
  /lib                <-- 마이바티스 *.jar 파일이 여기 있다.
  /src
    /org/myapp/
      /action
      /data           <-- 마이바티스 산출물이 여기 있다. Mapper 클래스, XML 설정, XML 매핑 파일들
        /mybatis-config.xml
        /BlogMapper.java
        /BlogMapper.xml
      /model
      /service
      /view
    /properties       <-- XML 설정파일에 포함된 프로퍼티들이 여기 있다.
  /test
    /org/myapp/
      /action
      /data
      /model
      /service
      /view
    /properties
  /web
    /WEB-INF
      /web.xml

이건 선호되는 형태이지 반드시 따라야 하는 요구사항이 아님을 기억해두라. 하지만 이러한 공통적인 형태를 사용하면 많은 사람들이 쉽게 이해할 것이다.

이 섹션의 나머지 예제는 디렉터리 구조가 이렇게 되어 있다고 가정하고 설명한다.

SqlSessions

마이바티스를 사용하기 위한 기본적인 자바 인터페이스는 SqlSession이다. 이 인터페이스를 통해 명령어를 실행하고 매퍼를 얻으며 트랜잭션을 관리 할 수 있다. 우리는 SqlSession에 대해서 좀더 얘기해볼 것이지만 먼저 SqlSession의 인스턴스를 만드는 방법을 배워보자. SqlSession은 SqlSessionFactory인스턴스를 사용해서 만든다. SqlSessionFactory는 몇가지 방법으로 SqlSession인스턴스를 생성하기 위한 메소드를 포함하고 있다. SqlSessionFactory자체는 XML, 애노테이션 또는 자바 설정에서 SqlSessonFactory를 생성할 수 있는 SqlSessionFactoryBuilder를 통해 만들어진다.

참고 스프링이나 쥬스와 같은 의존성 삽입 프레임워크와 함께 사용할때 SqlSessions은 DI프레임워크에 의해 생성되고 삽입된다. 그래서 SqlSessionFactoryBuilder나 SqlSessionFactory가 필요하지 않을 것이기 때문에 SqlSession섹션으로 바로 넘어가도 무방하다. 추가적인 정보는 MyBatis-Spring이나 MyBatis-Guice를 참고하길 바란다.

SqlSessionFactoryBuilder

SqlSessionFactoryBuilder는 5개의 build() 메소드를 가진다. 각각은 서로 다른 소스에서 SqlSessionFactory을 빌드한다.

SqlSessionFactory build(InputStream inputStream)
SqlSessionFactory build(InputStream inputStream, String environment)
SqlSessionFactory build(InputStream inputStream, Properties properties)
SqlSessionFactory build(InputStream inputStream, String env, Properties props)
SqlSessionFactory build(Configuration config)

처음 4개의 메소드가 가장 공통적이다. XML 문서를 나타내는 Reader 인스턴스를 가진다. SqlMapConfig.xml 파일은 위에서 다루었다. 선택적으로 사용가능한 프로퍼티는 environment와 properties이다. environment는 데이터소스와 트랜잭션 관리자를 포함하여 로드할 환경을 판단한다. 예를들면:

<environments default="development">
  <environment id="development">
    <transactionManager type="JDBC">
        ...
    <dataSource type="POOLED">
        ...
  </environment>
  <environment id="production">
    <transactionManager type="MANAGED">
        ...
    <dataSource type="JNDI">
        ...
  </environment>
</environments>

environment파라미터를 가진 메소드를 호출한다면 마이바티스는 사용할 환경을 위한 설정을 사용할 것이다. 물론 잘못된 환경설정을 사용하면 에러를 보게 될 것이다. environment파라미터를 가지지 않는 메소드 중 하나를 호출한다면 디폴트 환경(위 예제에서 default=“development”)이 사용될 것이다.

properties인스턴스를 가진 메소드를 호출하면 마이바티스는 프로퍼티들을 로드해서 설정에서 사용가능한 부분을 사용할 것이다. 프로퍼티들은 ${propName}와 같은 문법을 사용해서 설정의 값으로 대체될 수 있다.

프로퍼티들은 SqlMapConfig.xml파일에서 사용되거나 직접 명시할 수 있다. 그러므로 프로퍼티들의 우선순위를 이해하는 것이 중요하다. 우리는 앞서 언급하긴 했지만 쉽게 이해할 수 있도록 다시 보여주도록 하겠다.


프로퍼티가 한개 이상 존재한다면 마이바티스는 일정한 순서로 로드한다.

  • properties엘리먼트에 명시된 속성을 가장 먼저 읽는다.
  • properties엘리먼트의 클래스패스 자원이나 url 속성으로 부터 로드된 속성을 두번재로 읽는다. 그래서 이미 읽은 값이 있다면 덮어쓴다.,
  • 마지막으로 메소드 파라미터로 전달된 속성을 읽는다. 앞서 로드된 값을 덮어쓴다

그래서 가장 우선순위가 높은 속성은 메소드의 파라미터로 전달된 값이고 그 다음은 자원및 url 속성이고 마지막은 properties 엘리먼트에 명시된 값이다.


요약해보면 처음 4개의 메소드는 사실 같지만 environment 그리고/또는 properties에 명시한 값을 오버라이드한다. mybatis-config.xml파일에서 SqlSessionFactory를 빌드하는 예제이다.

String resource = "org/mybatis/builder/mybatis-config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(inputStream);

Resources유틸리티 클래스를 사용하고 있는 것을 주의깊게 보면 된다. 이 클래스는 org.apache.ibatis.io 패키지에 있다. Resources 클래스는 그 이름이 나타내는 것처럼 클래스패스나 파일 시스템 또는 웹 URL 에서 자원으로 로드하도록 해준다. IDE를 통해 클래스의 소스 코드를 보는 것으로 유용한 메소드를 보게 될 것이다. 그 유용한 메소드 목록들이다.

URL getResourceURL(String resource)
URL getResourceURL(ClassLoader loader, String resource)
InputStream getResourceAsStream(String resource)
InputStream getResourceAsStream(ClassLoader loader, String resource)
Properties getResourceAsProperties(String resource)
Properties getResourceAsProperties(ClassLoader loader, String resource)
Reader getResourceAsReader(String resource)
Reader getResourceAsReader(ClassLoader loader, String resource)
File getResourceAsFile(String resource)
File getResourceAsFile(ClassLoader loader, String resource)
InputStream getUrlAsStream(String urlString)
Reader getUrlAsReader(String urlString)
Properties getUrlAsProperties(String urlString)
Class classForName(String className)

마지막 build메소드는 Configuration의 인스턴스를 가진다. Configuration클래스는 SqlSessionFactory 인스턴스에 대해 알 필요가 있는 모든 것으로 가지고 있다. Configuration클래스는 SQL Map을 찾거나 관리하는 것을 포함하여 설정을 살펴보기 위해 유용하다. Configuration클래스는 앞서 봤던 모든 설정을 처리할 수 있으며 자바 API 로 나타낼 수 있다. SqlSessionFactory를 생성하기 위해 Configuration인스턴스를 build()메소드에 전달하는 예제이다.

DataSource dataSource = BaseDataTest.createBlogDataSource();
TransactionFactory transactionFactory = new JdbcTransactionFactory();

Environment environment = new Environment("development", transactionFactory, dataSource);

Configuration configuration = new Configuration(environment);
configuration.setLazyLoadingEnabled(true);
configuration.setEnhancementEnabled(true);
configuration.getTypeAliasRegistry().registerAlias(Blog.class);
configuration.getTypeAliasRegistry().registerAlias(Post.class);
configuration.getTypeAliasRegistry().registerAlias(Author.class);
configuration.addMapper(BoundBlogMapper.class);
configuration.addMapper(BoundAuthorMapper.class);

SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
SqlSessionFactory factory = builder.build(configuration);

이제 SqlSessionFactory를 만들었다. SqlSession인스턴스를 만들기 위해 사용해보자.

SqlSessionFactory

SqlSessionFactory는 SqlSession인스턴스를 생성하기 위해 사용할 수 있는 6개의 메소드를 가지고 있다. 6개의 메소드가 선택해서 사용하는 것들을 보자.

  • Transaction: 세션에서 트랜잭션 스코프 또는 자동 커밋을 사용하고 싶은가?
  • Connection: 설정된 DataSource에서 Connection 을 회득하고 싶은가?
  • Execution: PreparedStatements그리고/또는 배치(insert, delete를 포함해서) 업데이트를 재사용하고 싶은가?

오버로드된 메소드인 openSession() 이 3가지를 적절히 혼합해서 사용할 수 있다.

SqlSession openSession()
SqlSession openSession(boolean autoCommit)
SqlSession openSession(Connection connection)
SqlSession openSession(TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level)
SqlSession openSession(ExecutorType execType)
SqlSession openSession(ExecutorType execType, boolean autoCommit)
SqlSession openSession(ExecutorType execType, Connection connection)
Configuration getConfiguration();

파라미터를 가지지 않는 디폴트 openSession()메소드는 다음과 같은 성격을 가진 SqlSession을 만들것이다.

  • 트랜잭션 스코프는 시작될 것이다.
  • Connection 객체는 활성화된 환경에 의해 설정된 DataSource인스턴스를 획득할 것이다.
  • 트랜잭션 격리 레벨은 드라이버나 데이터소스가 디폴트로 제공하는 옵션을 사용할 것이다.
  • PreparedStatements는 재사용되지 않을 것이다. 그리고 update또한 배치처리되지 않을 것이다.

메소드 대부분은 그 이름과 파라미터가 그 역할을 충분히 설명한다. 자동커밋을 활성화하기 위해서 autoCommit파라미터에 “true” 값을 설정하라. 자체적인 커넥션을 제공하기 위해서는 connection파라미터에 Connection인스턴스를 설정하라.

Connection 과 autoCommit 둘다 설정하는 것을 오버라이드하지 않는다. 왜냐하면 마이바티스는 제공된 connection 객체를 설정할때마다 현재 사용중인 것을 사용한다. 마이바티스는 TransactionIsolationLevel라고 불리는 트랜잭션 격리 레벨을 위한 자바 enum 래퍼를 사용한다. JDBC를 5가지를 지원한다(NONE, READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE).

새롭게 보일수 있는 하나의 파라미터는 ExecutorType이다. enum으로는 3개의 값을 정의한다.

  • ExecutorType.SIMPLE: 이 타입의 실행자는 아무것도 하지 않는다. 구문 실행마다 새로운 PreparedStatement를 생성한다.
  • ExecutorType.REUSE: 이 타입의 실행자는 PreparedStatements를 재사용할 것이다.
  • ExecutorType.BATCH: 이 실행자는 모든 update구문을 배치처리하고 중간에 select 가 실행될 경우 필요하다면 경계를 표시한다. 이러한 과정은 행위를 좀더 이해하기 쉽게 하기 위함이다.

참고 SqlSessionFactory에서 언급하지 않는 한개 이상의 메소드가 있다. getConfiguration() 메소드인데 이 메소드는 런타임시 마이바티스 설정을 조사하는 Configuration인스턴스를 리턴할 것이다.

참고 마이바티스 이전 버전을 사용했다면 세션, 트랜잭션 그리고 배치들을 여기저기서 찾게 될 것이다. 이것들은 더이상 사용되지 않는다. 세가지 모두 세션의 범위에 모두 포함되었다. 이것들이 제공하던 모든 기능을 사용하기 위해 각각이 필요한 것 아니다.

SqlSession

앞서 언급한 것처럼 SqlSession인스턴스는 마이바티스에서 굉장히 강력한 클래스이다. 구문을 실행하고 트랜잭션을 커밋하거나 롤백하는 그리고 mapper인스턴스를 습득하기 위해 필요한 모든 메소드를 찾을 수 있을 것이다.

SqlSession에는 20개 이상의 메소드가 있다. 좀더 적절히 모아서 보도록 하자.

구문을 실행하는 메소드

이 메소드들은 SQL 매핑 XML 파일에 정의된 SELECT, INSERT, UPDATE 그리고 DELETE 구문을 실행하기 위해 사용된다. 메소드 이름 자체가 그 역할을 설명하도록 명명되었다. 메소드 각각은 구문의 ID 와 파라미터 객체(원시타입, 자바빈, POJO 또는 Map)을 가진다.

<T> T selectOne(String statement, Object parameter)
<E> List<E> selectList(String statement, Object parameter)
<T> Cursor<T> selectCursor(String statement, Object parameter)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey)
int insert(String statement, Object parameter)
int update(String statement, Object parameter)
int delete(String statement, Object parameter)

selectOne과 selectList의 차이점은 selectOne메소드는 오직 하나의 객체만을 리턴해야 한다는 것이다. 한개 이상을 리턴하거나 null 이 리턴된다면 예외가 발생할 것이다. 얼마나 많은 객체가 리턴될지 모른다면 selectList를 사용하라. 객체의 존재여부를 체크하고 싶다면 개수를 리턴하는 방법이 더 좋다. selectMap은 결과 목록을 Map으로 변환하기 위해 디자인된 특별한 경우이다. 이 경우 결과 객체의 프로퍼티 중 하나를 키로 사용하게 된다. 모든 구문이 파라미터를 필요로 하지는 않기 때문에 파라미터 객체를 요구하지 않는 형태로 오버로드되었다.

insert, update 그리고 delete 메소드에 의해 리턴되는 값은 실행된 구문에 의해 영향을 받은 레코드수를 표시한다.

<T> T selectOne(String statement)
<E> List<E> selectList(String statement)
<T> Cursor<T> selectCursor(String statement)
<K,V> Map<K,V> selectMap(String statement, String mapKey)
int insert(String statement)
int update(String statement)
int delete(String statement)

Cursor는 List와 동일한 결과를 보여주지만, 데이터를 반복문을 통해 지연로딩을 한다.

try (Cursor<MyEntity> entities = session.selectCursor(statement, param)) {
   for (MyEntity entity:entities) {
      // process one entity
   }
}

마지막으로 리턴되는 데이터의 범위를 제한하거나 결과를 핸들링 하는 로직을 부여할 수 있는 3개의 select 메소드가 있다.

<E> List<E> selectList (String statement, Object parameter, RowBounds rowBounds)
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds)
<K,V> Map<K,V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowbounds)
void select (String statement, Object parameter, ResultHandler<T> handler)
void select (String statement, Object parameter, RowBounds rowBounds, ResultHandler<T> handler)

RowBounds 파라미터는 마이바티스로 하여금 특정 개수 만큼의 레코드를 건너띄게 한다. RowBounds클래스는 offset과 limit 둘다 가지는 생성자가 있다.

int offset = 100;
int limit = 25;
RowBounds rowBounds = new RowBounds(offset, limit);

가장 좋은 성능을 위해 결과셋의 타입을 SCROLL_SENSITIVE나 SCROLL_INSENSITIVE로 사용하라.

ResultHandler파라미터는 레코드별로 다룰수 있도록 해준다. List에 추가할수도 있고 Map, Set을 만들수도 있으며 각각의 결과를 그냥 던질수도 있다. ResultHandler로 많은 것을 할 수 있고 마이바티스는 결과셋을 다루기 위해 내부적으로 사용한다.

Since 3.4.6, ResultHandler passed to a CALLABLE statement is used on every REFCURSOR output parameter of the stored procedure if there is any.

인터페이스는 매우 간단하다.

package org.apache.ibatis.session;
public interface ResultHandler<T> {
  void handleResult(ResultContext<? extends T> context);
}

ResultContext파라미터는 결과 객체에 접근할 수 있도록 해준다.

ResultHandler를 사용할 때 유의해야 할 제약사항이 2개 있다:

  • ResultHandler를 사용하여 호출된 메소드의 데이터는 캐싱 되지 않는다.
  • 고급 resualtMap을 사용할 경우, 마이바티스는 객체를 완성하기 위해 여러 줄의 코드를 필요로 할 수 있다. ResultHandler를 사용할 때 받는 객체는 associations나 collections가 완전히 채워지지 않은 상태일 수도 있다.
배치 수정시 flush메소드

어떤 시점에 JDBC드라이버 클래스에 저장된 배치 수정구문을 지울(flushing(executing)) 방법이 있다. 이 방법은 ExecutorTypeExecutorType.BATCH로 설정한 경우 사용가능하다.

List<BatchResult> flushStatements()
트랙잭션 제어 메소드

트랜잭션을 제어하기 위해 4개의 메소드가 있다. 물론 자동커밋을 선택하였거나 외부 트랜잭션 관리자를 사용하면 영향이 없다. 어쨌든 Connection인스턴스에 의해 관리되고 JDBC 트랜잭션 관리자를 사용하면 이 4개의 메소드를 사용할 수 있다.

void commit()
void commit(boolean force)
void rollback()
void rollback(boolean force)

기본적으로 마이바티스는 insert, update, delete 또는 affectData가 활성화된select 를 호출하여 데이터베이스가 변경된 것으로 감지하지 않는 한 실제로 커밋하지 않는다. 이러한 메소드 호출없이 변경되면 커밋된 것으로 보장하기 위해 commit 와 rollback 메소드에 true 값을 전달한다.

참고 MyBatis-Spring 과 MyBatis-Guice는 선언적인 트랜잭션 관리기법을 제공한다. 그래서 스프링이나 쥬스와 함께 마이바티스를 사용한다면 해당되는 메뉴얼을 꼭 참고하길 바란다.

세션 레벨의 캐시를 지우기
void clearCache()

SqlSession인스턴스는 update, commit, rollback 또는 close 할때마다 지워지는 로컬 캐시이다. 명시적으로 닫기 위해서는 clearCache()메소드를 호출할 수 있다.

SqlSession 을 반드시 닫도록 한다.
void close()

반드시 기억해야 하는 중요한 것은 당신이 열었던 세션을 닫아주는 것이다. 확실히 하기 위해 가장 좋은 방법은 다음과 같은 형태로 개발하는 것이다.

try (SqlSession session = sqlSessionFactory.openSession()) {
    // 다음의 3줄은 "어떤 작업을 하는"을 나타낸다.
    session.insert(...);
    session.update(...);
    session.delete(...);
    session.commit();
}

참고 SqlSessionFactory 처럼 SqlSession이 getConfiguration()메소드를 호출하여 Configuration 인스턴스를 얻을 수 있다.

Configuration getConfiguration()
Mappers 사용하기
<T> T getMapper(Class<T> type)

다양한 insert, update, delete 그리고 select 메소드는 강력하지만 다소 장황하고 타입에 안전하지 않다. 더군다나 IDE나 단위 테스트에 그다지 도움이 되지 않는 형태이다. 우리는 Mapper를 사용하는 예제는 이미 시작하기 섹션에서 봤다.

그러므로 매핑된 구문을 실행하기 위해 좀더 공통적인 방법은 Mapper클래스를 사용하는 것이다. Mapper클래스는 SqlSession 메소드에 일치하는 메소드와 간단히 연동된다. 다음의 예제 클래스는 몇가지 메소드 시그니처와 SqlSession에 매핑하는 방법을 보여준다.

public interface AuthorMapper {
  // (Author) selectOne("selectAuthor",5);
  Author selectAuthor(int id);
  // (List<Author>) selectList(“selectAuthors”)
  List<Author> selectAuthors();

  // (Map<Integer,Author>) selectMap("selectAuthors", "id")
  @MapKey("id")
  List<Author> selectAuthorsAsMap();
  // insert("insertAuthor", author)
  int insertAuthor(Author author);
  // updateAuthor("updateAuthor", author)
  int updateAuthor(Author author);
  // delete("deleteAuthor",5)
  int deleteAuthor(int id);
}

아주 간결하게 각각의 Mapper메소드 시그니처는 SqlSession 의 메소드 시그니처와 일치해야만 한다. String 파라미터 ID가 없지만 대신 메소드명은 매핑된 구문의 ID 와 같아야 한다.

추가로 리턴 타입은 기대하는 결과 타입과 일치해야만 한다. 원시타입과 Map, POJO 그리고 자바빈등 대부분의 타입이 지원된다.

참고 Mapper 인터페이스는 어떠한 인터페이스를 구현할 필요가 없고 어떠한 클래스를 확장할 필요도 없다. 메소드 시그니처는 관련된 매핑된 구문을 유일하게 확인하기 위해 사용될 수 있다.

참고 Mapper 인터페이스는 다른 인터페이스를 확장할 수 있다. 적절한 명명공간의 구문은 Mapper 인터페이스에 XML바인딩을 사용한다. 오직 하나의 제한점은 두개의 인터페이스에 같은 메소드 시그니처를 사용할 수 없다는 것이다.

mapper 메소드에 여러개의 파라미터를 전달 할 수 있다. 여러개의 파라미터를 전달하면 파라미터 목록의 위치에 따라 명명될 것이다. 예를 들면 #{param1}, #{param2} 기타 등등 이런 식이다. 만약 파라미터의 이름을 변경하고자 한다면 파라미터의 @Param(“paramName”)애노테이션을 사용할 수 있다.

쿼리 결과를 제한하기 위해 메소드에 RowBounds인스턴스를 전달 할 수 있다.

Mapper 애노테이션

이 프레임워크가 만들어진 이후로 마이바티스는 XML 기반의 프레임워크이다. 설정은 XML기반이고 매핑된 구문또한 XML 에 정의한다. 마이바티스 3 에서는 새로운 추가 옵션이 생겼다. 마이바티스 3 은 편리하고 강력한 자바 기반의 설정 API 를 제공한다. 설정 API 는 XML 기반의 마이바티스 설정의 기초가 된다. 이는 새로운 애노테이션 기반의 설정에도 그대로 적용된다. 애노테이션은 소개하는데 많은 시간이 할애하지 않아도 될 정도로 매핑된 구문을 구현하는 간단한 방법을 제공한다.

참고 자바 애노테이션은 복잡하고 유연해야 하는 경우에 대해서는 다소 제한적이다. 조사하는데 많은 시간이 소요됨에도 불구하고 가장 강력한 마이바티스 매핑은 애노테이션으로 처리되지는 못한다. C# 속성은 이러한 제한사항이 없어서 MyBatis.NET 버전은 XML 대안으로 자바보다 다소 더 풍부한 기능을 제공한다. 하지만 자바 애노테이션 기반의 설정이 장점이 없지는 않다.

사용가능한 애노테이션은 아래에서 설명한다.

애노테이션 대상 XML 엘리먼트 설명
@CacheNamespace Class <cache> 명명공간을 위한 캐시 설정 사용가능한 속성들 : implementation, eviction, flushInterval, size, readWrite, blocking 그리고 properties.
@Property N/A <property> property 값 또는 placeholder(mybatis-config.xml 에 정의된 configuration properties 로 대체 할 수 있음) 를 지정한다. 사용가능한 속성들: name, value. (MyBatis 3.4.2 이상에서 사용 가능)
@CacheNamespaceRef Class <cacheRef> 다른 명명공간의 캐시에 대한 참조 Note that caches declared in an XML mapper file are considered a separate namespace, even if they share the same FQCN. 사용가능한 속성들 : value, name. 이 annotation 을 사용하려면 value 또는 name 속성을 지정해야 한다. value 속성은 namespace(namespace 이름은 지정된 java type 의 FQCN 이 된다) 를 나타내는 java type 을 지정한다, 그리고 name 속성(이 속성은 3.4.2 부터 사용가능하다) 은 namespace 를 나타내는 이름을 지정한다.
@ConstructorArgs Method <constructor> 결과 객체 생성자에 전달되는 결과들 사용가능한 속성들 : value(인자의 배열)
@Arg N/A
  • <arg>
  • <idArg>
ConstructorArgs 의 일부로 한개의 생성자 인자 사용가능한 속성들 : id, column, javaType, jdbcType, typeHandler, select 그리고 resultMap. id 속성은 비교하기 위해 사용되는 값이다. XML에서는 <idArg> 엘리먼트와 유사하다. Since 3.5.4, it can be used as repeatable annotation.
@TypeDiscriminator Method <discriminator> 결과매핑을 할때 사용될 수 있는 경우에 대한 값들 사용가능한 속성들 : column, javaType, jdbcType, typeHandler, cases. cases 속성은 경우(case)의 배열이다.
@Case N/A <case> case 의 값과 매핑 사용가능한 속성들 : value, type, results. results 속성은 Result 의 배열이다. 게다가 이 Case 애노테이션은 Results애노테이션에서 명시된 ResultMap과 유사하다.
@Results Method <resultMap> 결과 칼럼이 프로퍼티나 필드에 매핑되는 방법에 대한 상세 설정을 포함하는 결과 매핑의 목록 사용가능한 속성들 : value(Result 애노테이션의 배열), id (결과매핑의 이름)
@Result N/A
  • <result>
  • <id>
칼럼이 프로퍼티나 필드에 매핑되는 한개의 결과 매핑 사용가능한 속성들 : id, column, property, javaType, jdbcType, typeHandler, one, many. id 속성은 프로퍼티를 비교할 때 사용할지를 표시하는 boolean 값이다. (XML 에서 <id> 와 유사하다.) one 속성은 한개의 관계(associations)이고 <association> 과 유사하다. many 속성은 collection이고 <collection> 과 유사하다. 클래스의 명명규칙 충돌을 피하기 위해 명명되었다. Since 3.5.4, it can be used as repeatable annotation.
@One N/A <association> 복잡한 타입의 한개의 프로퍼티를 위한 매핑이다. 사용가능한 속성들 : select(매핑 구문의 이름, 예를들어 매퍼 메소드). fetchType, which supersedes the global configuration parameter lazyLoadingEnabled for this mapping. resultMap(available since 3.5.5), which is the fully qualified name of a result map that map to a single container object from select result. columnPrefix(available since 3.5.5), which is column prefix for grouping select columns at nested result map. Note: 조인 매핑은 애노테이션 API 를 통해서는 지원되지 않는다는 것을 알아야 한다. 순환(circular) 참조를 허용하지 않는 자바 애노테이션의 제약사항때문이다.
@Many N/A <collection> 복잡한 타입의 collection 프로퍼티를 위한 매핑이다. 사용가능한 속성들 : select(매핑 구문의 이름, 예를들어 매퍼 메소드) fetchType, which supersedes the global configuration parameter lazyLoadingEnabled for this mapping. resultMap(available since 3.5.5), which is the fully qualified name of a result map that map to collection object from select result. columnPrefix(available since 3.5.5), which is column prefix for grouping select columns at nested result map. Note: 조인 매핑은 애노테이션 API 를 통해서는 지원되지 않는다는 것을 알아야 한다. 순환(circular) 참조를 허용하지 않는 자바 애노테이션의 제약사항때문이다.
@MapKey Method 리턴 타입이 Map 인 메소드에서 사용된다. 결과객체의 List 를 객체의 프로퍼티에 기초한 Map으로 변환하기 위해 사용된다.
@Options Method 매핑 구문의 속성들 이 애노테이션은 매핑된 구문에 속성으로 존재하는 많은 분기(switch)와 설정 옵션에 접근할 수 있다. 각 구문을 복잡하게 만들기 보다 Options 애노테이션으로 일관되고 깔끔한 방법으로 설정 할수 있게 한다. 사용가능한 속성들 : useCache=true, flushCache=FlushCachePolicy.DEFAULT, resultSetType=DEFAULT, statementType=PREPARED, fetchSize=-1, timeout=-1, useGeneratedKeys=false, keyProperty=“”, keyColumn=“”, resultSets=“”, databaseId="". 자바 애노테이션을 이해하는 것이 중요하다. 자바 애노테이션은 “null”을 설정 할 수 없다. 그래서 일단 Options 애노테이션을 사용하면 각각의 속성은 디폴트 값을 사용하게 된다. 디폴트 값이 기대하지 않은 결과를 만들지 않도록 주의해야 한다. The databaseId(Available since 3.5.5), in case there is a configured DatabaseIdProvider, the MyBatis use the Options with no databaseId attribute or with a databaseId that matches the current one. If found with and without the databaseId the latter will be discarded.

keyColumn은 키 칼럼이 테이블의 첫번째 칼럼이 아닌 특정 데이터베이스에서만(PostgreSQL 같은) 필요하다.
  • @Insert
  • @Update
  • @Delete
  • @Select
Method
  • <insert>
  • <update>
  • <delete>
  • <select>
각각의 애노테이션은 실행하고자 하는 SQL을 표현한다. 각각 문자열의 배열(또는 한개의 문자열)을 가진다. 문자열의 배열이 전달되면, 각각 공백을 두고 하나로 합친다. 자바 코드에서 SQL 을 만들때 발행할 수 있는 “공백 누락” 문제를 해결하도록 도와준다. 사용가능한 속성들 : value(한개의 SQL 구문을 만들기 위한 문자열의 배열). The databaseId(Available since 3.5.5), in case there is a configured DatabaseIdProvider, the MyBatis use a statement with no databaseId attribute or with a databaseId that matches the current one. If found with and without the databaseId the latter will be discarded.
  • @InsertProvider
  • @UpdateProvider
  • @DeleteProvider
  • @SelectProvider
Method
  • <insert>
  • <update>
  • <delete>
  • <select>
실행시 SQL 을 리턴할 클래스 과 메소드명을 명시하도록 해주는 대체수단의 애노테이션이다 (Since 3.4.6, you can specify the CharSequence instead of String as a method return type). 매핑된 구문을 실행할 때 마이바티스는 클래스의 인스턴스를 만들고 메소드를 실행한다. Mapper 메서드의 인수인 "Mapper interface type" and "Database ID" 과 ProviderContext(Mybatis 3.4.5 부터) 를 이용한 "Mapper method" 로 전달 된 객체를 메서드 매개변수로 전달할 수 있다.(마이바티스 3.4이상에서는 복수 파라미터를 허용한다.) 사용가능한 속성들 : value, type, method. value and type 속성은 클래스 (The type attribute is alias for value, you must be specify either one. But both attributes can be omit when specify the defaultSqlProviderType as global configuration). method 속성은 메소드명이다 (Since 3.5.1, you can omit method attribute, the MyBatis will resolve a target method via the ProviderMethodResolver interface. If not resolve by it, the MyBatis use the reserved fallback method that named provideSql). The databaseId(Available since 3.5.5), in case there is a configured DatabaseIdProvider, the MyBatis will use a provider method with no databaseId attribute or with a databaseId that matches the current one. If found with and without the databaseId the latter will be discarded. Note: 이 섹션은 클래스에 대한 설명으로 동적 SQL 을 좀더 깔끔하고 읽기 쉽게 만드는데 도움이 될 수 있다.
@Param Parameter N/A 매퍼 메소드가 여러개의 파라미터를 가진다면 이 애노테이션은 이름에 일치하는 매퍼 메소드 파라미터에 적용된다. 반면에 여러개의 파라미터는 순서대로 명명된다. 예를들어 #{param1}, #{param2} 등이 디폴트다. @Param(“person”)을 사용하면 파라미터는 #{person}로 명명된다.
@SelectKey Method <selectKey> 이 애노테이션은 @Insert, @InsertProvider, @Update 또는 @UpdateProvider 애노테이션을 사용하는 메소드에서 <selectKey>와 똑같다. 다른 메소드에서는 무시된다. @SelectKey애노테이션을 명시하면 마이바티스는 @Options애노테이션이나 설정 프로퍼티를 통해 설정된 key프로퍼티를 무시할 것이다. 사용가능한 속성들 : statement는 실행할 SQL 구문을 만드는 문자열의 배열이다. keyProperty는 새로운 값으로 수정될 파라미터 객체의 프로퍼티이다. SQL이 insert 전후에 실행되는 것을 나타내기 위해 true나 false가 되어야 한다. resultType은 keyProperty의 자바 타입이다. statementType=PREPARED. The databaseId(Available since 3.5.5), in case there is a configured DatabaseIdProvider, the MyBatis will use a statement with no databaseId attribute or with a databaseId that matches the current one. If found with and without the databaseId the latter will be discarded.
@ResultMap Method N/A 이 애노테이션은 @Select또는 @SelectProvider애노테이션을 위해 XML 매퍼의 <resultMap> 엘리먼트의 id를 제공하기 위해 사용된다. XML 에 정의된 결과매핑을 재사용하도록 해준다. 이 애노테이션은 @Results나 @ConstructorArgs를 오버라이드 할 것이다.
@ResultType Method N/A 이 애노테이션은 결과 핸들러를 사용할때 사용한다. 이 경우 리턴타입은 void이고 마이바티스는 각각의 레코드 정보를 가지는 객체의 타입을 결정하는 방법을 가져야만 한다. XML 결과매핑이 있다면 @ResultMap 애노테이션을 사용하자. 결과타입이 XML에서 <select> 엘리먼트에 명시되어 있다면 다른 애노테이션이 필요하지 않다. 결과타입이 XML에서 <select> 엘리먼트에 명시되어 있지 않은 경우에 이 애노테이션을 사용하자. 예를들어 @Select 애노테이션이 선언되어 있다면 메소드는 결과 핸들러를 사용할 것이다. 결과 타입은 void여야만 하고 이 애노테이션(이나 @ResultMap)을 반드시 사용해야 한다. 이 애노테이션은 메소드 리턴타입이 void가 아니라면 무시한다.
@Flush Method N/A 이 애노테이션을 사용하면 매퍼 인터페이스에 정의한 메소드를 통해 SqlSession#flushStatements()를 호출한다.(마이바티스 3.3과 이상의 버전)
Mapper애노테이션 예제

이 예제는 insert 하기전에 일련번호를 가져오기 위해 @SelectKey 애노테이션을 사용하는 것을 보여준다.

@Insert("insert into table3 (id, name) values(#{nameId}, #{name})")
@SelectKey(statement="call next value for TestSequence", keyProperty="nameId", before=true, resultType=int.class)
int insertTable3(Name name);

이 예제는 insert한 후에 값을 가져오기 위해 @SelectKey애노테이션을 사용하는 것으로 보여준다.

@Insert("insert into table2 (name) values(#{name})")
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class)
int insertTable2(Name name);

이 예제는 SqlSession#flushStatements()를 호출하기 위해 @Flush애노테이션을 사용했다.

@Flush
List<BatchResult> flush();

다음 예제는 @Results애노테이션의 id속성을 명시해서 결과매핑을 명명하는 방법을 보여준다.

@Results(id = "userResult", value = {
  @Result(property = "id", column = "uid", id = true),
  @Result(property = "firstName", column = "first_name"),
  @Result(property = "lastName", column = "last_name")
})
@Select("select * from users where id = #{id}")
User getUserById(Integer id);

@Results(id = "companyResults")
@ConstructorArgs({
  @Arg(column = "cid", javaType = Integer.class, id = true),
  @Arg(column = "name", javaType = String.class)
})
@Select("select * from company where id = #{id}")
Company getCompanyById(Integer id);

다음 예제는 Sql 프로바이더 애노테이션을 사용해서 파라미터 한개를 처리하는 방법을 보여준다.

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(String name);

class UserSqlBuilder {
  public static String buildGetUsersByName(final String name) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      if (name != null) {
        WHERE("name like #{value} || '%'");
      }
      ORDER_BY("id");
    }}.toString();
  }
}

다음 예제는 Sql 프로바이더 애노테이션을 사용해서 파라미터 여러개를 처리하는 방법을 보여준다.

@SelectProvider(type = UserSqlBuilder.class, method = "buildGetUsersByName")
List<User> getUsersByName(
    @Param("name") String name, @Param("orderByColumn") String orderByColumn);

class UserSqlBuilder {

  // @Param애노테이션을 사용하지 않으면 매퍼 메소드와 동일한 인자를 정의해야만 한다.
  public static String buildGetUsersByName(
      final String name, final String orderByColumn) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      WHERE("name like #{name} || '%'");
      ORDER_BY(orderByColumn);
    }}.toString();
  }

  // @Param애노테이션을 사용한다면, 오직 사용할 인자만 정의할 수 있다.
  public static String buildGetUsersByName(@Param("orderByColumn") final String orderByColumn) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      WHERE("name like #{name} || '%'");
      ORDER_BY(orderByColumn);
    }}.toString();
  }
}

이 예제는 모든 매퍼 메소드에 SQL 프로바이더 클래스를 전역 설정으로 공유하는 방법을 보여준다. (3.5.6 버전부터 사용 가능):


Configuration configuration = new Configuration();
configuration.setDefaultSqlProviderType(TemplateFilePathProvider.class); // 모든 mapper 메소드에 공유할 시, SQL 프로바이더 클래스를 지정한다.
// ...

// sql provider 애노테이션에서 type/value 속성을 생략할 수 있다.
// 생략시, 마이바티스는 defaultSqlProviderType으로 지정된 클래스를 적용한다.
public interface UserMapper {

  @SelectProvider // @SelectProvider(TemplateFilePathProvider.class) 와 동일하다.
  User findUser(int id);

  @InsertProvider // @InsertProvider(TemplateFilePathProvider.class) 와 동일하다.
  void createUser(User user);

  @UpdateProvider // @UpdateProvider(TemplateFilePathProvider.class) 와 동일하다.
  void updateUser(User user);

  @DeleteProvider // @DeleteProvider(TemplateFilePathProvider.class) 와 동일하다.
  void deleteUser(int id);
}

이 예제는 ProviderMethodResolver의 기본 구현 사용법을 보여준다.(MyBatis 3.5.1 버전 이상부터 사용가능):

@SelectProvider(UserSqlProvider.class)
List<User> getUsersByName(String name);

// provider 클래스에서 ProviderMethodResolver 를 구현한다.
class UserSqlProvider implements ProviderMethodResolver {
  // In default implementation, it will resolve a method that method name is matched with mapper method
  // 기본 구현에서, 메소드 이름이 mapper 메소드와 일치하는 경우 해당 메소드를 찾는다.
  public static String getUsersByName(final String name) {
    return new SQL(){{
      SELECT("*");
      FROM("users");
      if (name != null) {
        WHERE("name like #{value} || '%'");
      }
      ORDER_BY("id");
    }}.toString();
  }
}

이 예제는 statement 애노테이션에서 databaseId 속성이 어떻게 활용되는지를 보여준다(3.5.5 버전부터 사용 가능):


@Select(value = "SELECT SYS_GUID() FROM dual", databaseId = "oracle") // DatabaseIdProvider가 "oracle"을 제공하면 이 구문을 사용한다.
@Select(value = "SELECT uuid_generate_v4()", databaseId = "postgres") // DatabaseIdProvider가 "postgres"를 제공하면 이 구문을 사용한다.
@Select("SELECT RANDOM_UUID()") // DatabaseIdProvider가 설정되지 않았거나 일치하는 databaseId가 없는 경우 이 구문을 사용한다.
String generateId();