분류 전체보기

MyBatis의 Cache 설정

2012. 8. 2. 16:31

MyBatis의 캐시를 적용해보니 Mapper 단위로 캐시가 사용되어 insert, update, delete 명령을 실행할 때,  flush가 실행되지 않으면 select 명령을 실행할 때 변경전 캐시 내용이 출력되는 문제점이 있었다. 물론 CRUD 단위로 작성된 Mapper 라면 문제가 없겠지만, 조인한 결과를 읽기 위한 Mapper의 경우 select 명령을 실행할 경우에도 flush를 해줘야 하므로 캐시 이용의 이점을 얻을 수 없었다.

캐시의 사용은 CRUD가 한 세트로 작성되는 mapper에서만 사용해야 할 것 같다.

Cache

MyBatis는 쉽게 설정 가능하고 변경 가능한 강력한 트랜젝션 쿼리 캐싱을 포함하고 있다. MyBatis 3 구현체는 더 강력하고 훨씨 쉽게 설정할 수 있도록 많은 변화가 있었다.

기본적으로, 세션 주기 동안 캐시 데이터가 전적으로 사용될 수 있도록 로컬 세션 캐싱만 활성화 되어 있다. Global level caching을 활성화 하기 위해 SQL Mapping 파일에 간단하게 한 줄만 추가하면 된다.

<cache/>

이 한 문장이 다음과 같은 영향을 준다:

  • 맵핑 구문 파일 내의 모든 select 구문의 결과는 캐싱될 것이다.
  • 매핑 구문 파일 내의 모든 insert, update, delete 구문은 캐시에서 비워질(flush) 것이다.
  • 캐시에서 내보내기 위해 LRU(Least Recently Used; 최빈값 이용) 알고리즘을 사용할 것이다.
  • 캐시는 시간 기반 스케줄로 캐시를 비우지 않을 것이다.(캐시를 비우는 간격이 없다.)
  • 캐시는 1,024개의 쿼리 결과를 담은 리스트나 객체들의 참조를 저장할 것이다.
  • 캐시는 읽기/쓰기 캐시처럼 취급할 것이다. 검색된 객체들은 다른 호출자나 스레드에 의해 잠재적인 수정이 없도록 공유되지 않고 안전하게 호출자에 의해 수정된다는 의미이다.
이 모든 속성들은 캐시 엘리먼트의 어트리뷰트들을 통해 수정될 수 있다. 예들 들어:
<cache eviction="FIFO" flushinterval="60000"
        size="500" readonly="true"/>

여기 더 발전된 설정은 60초마다 캐시를 FIFO(선입선출) 방식으로 비우고, 512개까지의 객체나 리스트들의 결과값을 저장하며, 객체는 읽기전용으로 사용된다. 따라서  스레드 안의 두 호출자 사이에서 수정하는 것은 충돌을 일으킬 수 있다.

가능한 캐시 내보내기 정책은 4가지가 가능하다:

  • LRU
  • FIFO
  • SOFT - Soft Reference: 가비지 컬렉터의 상태와 Soft Reference 규칙에 의해 삭제된다.
  • WEAK - Weak Reference: 가비지 컬렉터의 상태와 Weak Reference 규칙에 의해 더 적극적으로 삭제된다.


스트럿츠2에서 리소스 번들을 이용하여 문자열을 출력하기 위해서는 ActionSupport를 상속받아 Action 클래스를 작성하여야 하며 방법은 다음과 같이 다양합니다.

  1. Action 클래스에서 출력
    ...
    public class MyAction extends ActionSupport {
        ...
        public void valid() {
            ...
            addFieldError("username", getText("username.required"));
        }
        ...
    }
    
  2. Property 액션 태그의 사용
    <s:property value="getText('username.required')"/>
    
  3. Text 액션 태그의 사용
    <s:text name="username.required"/>
  4. 액션 태그내의 Key 속성 사용
    <s:textfield key="username.required"/>
    
  5. i18n 액션 태그의 사용
    
        <s:text name="username.required"/>
    

리소스 번들은 다음과 같은 순서로 적용됩니다.

  1. ActionClass.propertie
  2. Interface.properties
  3. BaseClass.properties
  4. ModelDriven's model
  5. package.properti
  6. i18n message key로 검색
  7. Global resource properties


Struts2는 Struts1과 달리 필터 기반으로 동작하기 때문에 Struts1과는 배포기술자(DD) 설정이 다릅니다. 특히 Struts 2.1.3 이후 버전부터는 기본 필터인 디스패처도 달라졌습니다.

...
...
    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    

    
        struts2
        /*
    

    


만일 Struts 2.1.3 버전이나 이전 버전으로 개발하기 위해서는 다음과 같이 디스패처를 지정합니다.(2.1.3이후 버전도 이전 버전과의 호환을 위해 지원하고 있습니다.)

...

    Struts2
    org.apache.struts2.dispatcher.FilterDispatcher
...

DB에 저장된 텍스트 중 개행(줄바꿈)문자를 <br> 태그로 바꿔야 할 필요가 있을 때가 종종 있습니다. 입력시에는 텍스트 박스를 이용하지만 브라우저에 텍스트를 뿌릴 때는 개행 위치마다 <br> 태그를 채워넣어야 하죠. 이럴 때, JSTL과 스크립틀릿을 사용하면 간단히 처리할 수 있습니다.

<% pageContext.setAttribute("LF", "\n"); %>

<c:cout> 액션 태그의 escapeXML 속성은 브라우저가 HTML 태그를 해석하여 브라우징할 수 있도록 해주며, fn:replace() 함수를 이용하여 개행문자를 <br> 태그로 바꿔줍니다. 이때 개행문자와 같은 이스케이프 문자는 액션태그가 해석을 할 수 없기 때문에 pageContext를 이용하여 page 생존범위에 LF라는 이름의 변수에 개행문자를 저장하고 fn:replace() 함수에서 사용할 수 있게 해줍니다.

날짜를 DB에 저장할 경우 작업의 편리함이나 효율을 위해 문자열 형태로 저장하거나 DB로부터 프리젠테이션 계층으로 불러올 때 문자열로 변환하여 불러올 경우가 많습니다. MySQL의 JDBC 문서를 봐도 Date 타입은 String 타입으로 매칭시키도록 하고 있습니다.

저의 경우 yyyy-MM-dd 형식의 문자열로 불러온 날짜값을 yyyy/MM/dd 형식으로 화면에 뿌릴 필요가 있었습니다. 물론 JavaScript를 이용하여 변환하거나, JSTL의 fn:replace() 함수를 이용하는 방법도 있겠으나, 둘 다 왠지 꼼수를 쓴다는 느낌이 강해서 정석대로 접근해 봤습니다.

문자열 → 날짜 값 → 날짜 형식 지정



fmt:parseDate 액션태그의 pattern 속성 값을 문자열 형식과 맞추어 해당 문자열을 날짜값date 변수에 저장한 뒤, 다시 fmt:formateDate 액션태그를 이용해서 날짜 형식을 지정해 줍니다. 간단한 예제지만 문자열을 다양한 형식의 날짜 형태로 간단히 뿌릴 수 있고 날짜값으로 변경하였기 때문에 날짜와 관련한 비교 등 연산도 유리합니다.

+ Recent posts