Whiteship's Note


[하이버네이트] 2차 캐싱 적용하기

Hibernate/etc : 2009.09.07 18:43


참조
Java Persistence With Hibernate
http://whiteship.tistory.com/1256
Improving Hibernate's Performance
19.2. The Second Level Cache
Hibernate: Truly Understanding the Second-Level and Query Caches
Hibernate Caching

이론적으로 정리할 것 들

- 2차 캐싱이라고 하는 이유? 1차 캐시(persistence context cache)는 있으니깐.
- 하이버네이트 캐싱 종류(트랜잭션 스콥 캐싱, 프로세스 스콥 캐싱, 클러스터 스콥 캐싱)
- 캐싱에 적당한 클래스(데이터 변경이 드물고, (금전적인 데이터 처럼)핵심적인 데이터가 아니며, 공유하는 데이터가 아니고 애플리케이션에 국한된 데이터)
- 동시성 전략(Transactional, Read-write, Nonstrict-read-write, Read-only)
- 캐싱 공급자 선택하기(EHCache, OSCache, SwarmCacahe, JBoss Cache)

적용하기

1. 캐싱 동시성 전략 선택하기

read-wirte 모드를 선택함. read committed isolation 수준을 유지하려고.

@Entity
@Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
public class Study implements Serializable{

2. SessionFactory 설정에 2차 캐싱 관련 설정 추가.

    <bean id="sessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="packagesToScan" value="springsprout.domain" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                <prop key="hibernate.cache.use_second_level_cache">true</prop>
                <prop key="hibernate.cache.use_query_cache">true</prop>
                <prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop>
            </props>
        </property>
    </bean>

2차 캐시와 함께 쿼리 캐시도 켜주고, 사용할 캐싱 공급자를 설정해 줍니다.

3. Query 또는 Criteria API에 cacheable 설정 true로 변경.

기본값이 false기 때문에 이렇게 해주지 않으면 캐시가 적용되지 않습니다.

    public List<Study> getStudyList() {
        Criteria c = getCurrentSession().createCriteria(Study.class);
        c.setCacheable(true);
        return c.list();
    }

4. 테스트

    @Test
    public void getAll() throws Exception {
        insertXmlData("testData.xml");
        assertThat(sr.getStudyList().size(), is(2));
        assertThat(sr.getStudyList().size(), is(2));
    }

콘솔에 select 쿼리가 한 번만 찍히는지 확인합니다.

5. (optional) ehcache.xml 설정 파일 추가.

<ehcache>
    <diskStore path="java.io.tmpdir"/>
    <defaultCache maxElementsInMemory="500" eternal="true"
        overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />
    <cache name="springsprout.domain.study.Study"
        maxElementsInMemory="500" eternal="true" overflowToDisk="false"
        memoryStoreEvictionPolicy="LFU" />
    <cache name="springsprout.domain.study.Meeting"
        maxElementsInMemory="500" eternal="true" overflowToDisk="false"
        memoryStoreEvictionPolicy="LFU" />
    <cache name="org.hibernate.cache.StandardQueryCache"
        maxElementsInMemory="5" eternal="false" timeToLiveSeconds="120"
        overflowToDisk="true" />
    <cache name="org.hibernate.cache.UpdateTimestampsCache"
        maxElementsInMemory="5000" eternal="true" overflowToDisk="true" />
</ehcache>

이런식으로 만든다음 src 폴더 바로 밑에 추가해주면 끝.

6. 고민하기

- 콘솔을 눈으로 확인하는;; 수동 테스트인데 이걸 어떻게 하면 자동화 테스트로 바꿀 수 있을까요. 흠..
- SessionFactory 자체에 아예 모든 Qeury와 Criteria가 캐시를 사용하도록 설정할 수는 없을까요?
- 스프링 AOP를 이용한 애플리케이션 차원의 캐시와 지금 사용한 시스템적인 캐시 중에 어떤것을 어떤 경우에 사용해야 적당한 것일까?

top


[hamcrest] Matcher 만들기

모하니?/Coding : 2009.09.07 10:59


hamcrest는 Mockito와 JUnit 등 테스트 관련 프레임워크에서 참조하는 라이브러리로, Matcher라는 개념을 제공해줍니다. 이것을 사용해서 테스트를 좀 더 간편하게 만들 수 있습니다.

예를 들어, 다음과 같은 테스트가 있습니다.

ConfirmMailTest

...
        Member member = new Member();
        member.setEmail("keesun@mail.com");
        member.setName("keesun");
        ConfirmMail mail = new ConfirmMail(member);
        assertThat(Arrays.asList(mail.getTos()), hasItem("keesun@mail.com"));
        assertThat(mail.makeMessage(), containsString("회원 인증 메일 입니다"));
        assertThat(mail.getFrom(), is("s2cmailer@gmail.com"));
        assertThat(mail.getSubject(), containsString("keesun"));
...

이 테스트에서 필요한 Matcher로 isAbout(Membe member)라는 것을 하나 만들고 다음과 같은 클래스를 정의합니다. 아. 그전에 위 테스트 코드를 미리 다음과 같이 수정해 두는 것이 좋겠습니다.

        Member member = new Member();
        member.setEmail("keesun@mail.com");
        member.setName("keesun");
        ConfirmMail mail = new ConfirmMail(member);
        assertThat(mail, isAbout(member));

그런다음 클래스를 정의합니다. 이 클래스는 Mockito의 ArgumentMatcher 클래스를 상속 받고, isAbout이라는 static 메서드를 제공해줍니다.

public class MailMatcher extends ArgumentMatcher<SpringSproutMail> {

    private String from;
    private String to;
    private String subject;
    private String message;

    public MailMatcher(String from, String to, String subject, String message) {
        super();
        this.from = from;
        this.to = to;
        this.subject = subject;
        this.message = message;
    }

    @Override
    public boolean matches(Object mail) {
        SpringSproutMail smail = (SpringSproutMail) mail;
        if (from != null && !from.equals(smail.getFrom()))
            return false;
        if (!Arrays.asList(smail.getTos()).contains(to))
            return false;
        if (!smail.getSubject().contains(subject))
            return false;
        if (!smail.makeMessage().contains(message))
            return false;
        return true;
    }

    public static Matcher<SpringSproutMail> isAbout(Member member) {
        return new MailMatcher(SpringSproutMail.SENDER_MAIL, member.getEmail(),
                member.getName(), "회원 인증 메일");
    }

}

배보다 배꼽이 큰거 아닌가 하는 생각이 들지만, 이 매처 클래스를 여러 메일 테스트에서 사용할 수 있도록 조금 손을 본다면 쓸만할 겁니다.

top







티스토리 툴바