[하이버네이트] @BatchSize로 쿼리 갯수 대폭 줄이기

참조:
http://docs.jboss.org/hibernate/core/3.3/reference/en/html/performance.html
http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/annotations/BatchSize.html

스터디의 회원은 각각 Collection<Study, Integer> 타입의 목록을 가지고 있습니다. 스터디당 참여율이나 신뢰도가 들어있는 콜렉션입니다. 그리고 스터디를 보여줄 때 각 회원들의 참여율과 신뢰도를 보여주도록 되어 있는데, 문제는 쿼리입니다.

Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id=?
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id=?

이런 쿼리가 회원 수*2 만큼 생성됩니다. 한 회원당 attendanceRate와 trustRate를 가지고 있기 떄문이죠. 바로 이런 경우 @BatchSize를 사용하면 쿼리를 대폭 줄일 수 있습니다. 설정은 간단하죠;

    @CollectionOfElements(targetElement = Integer.class)
    @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
    @BatchSize(size=30)
    private Map<Study, Integer> studyAttendanceRates;

    @CollectionOfElements(targetElement = Integer.class)
    @Cache(usage=CacheConcurrencyStrategy.READ_WRITE)
    @BatchSize(size=30)
    private Map<Study, Integer> studyTrustRates;

설정을 한 뒤 쿼리 갯수는 대폭 줄어들게 됩니다. 물론 그만큼 빨라지죠.

Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id in (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
Hibernate: select studytrust0_.Member_id as Member1_0_, studytrust0_.element as element0_, studytrust0_.mapkey_id as mapkey3_0_ from Member_studyTrustRates studytrust0_ where studytrust0_.Member_id in (?, ?)
Hibernate: select studyatten0_.Member_id as Member1_0_, studyatten0_.element as element0_, studyatten0_.mapkey_id as mapkey3_0_ from Member_studyAttendanceRates studyatten0_ where studyatten0_.Member_id in (?, ?)

[메이븐] 하이버네이트 플러그인

참조:
http://kwon37xi.springnote.com/pages/2275410
http://mojo.codehaus.org/maven-hibernate3/hibernate3-maven-plugin/componentproperties.html

1. 메이븐 pom.xml 에 플러그인 추가하기

            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>hibernate3-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <componentProperties>
                        <drop>false</drop>
                        <create>true</create>
                        <format>true</format>
                        <export>false</export>
                        <jdk5>true</jdk5>
                        <outputfilename>schema.ddl</outputfilename>
                        <configurationfile>src/hibernate.cfg.xml</configurationfile>
                        <propertyfile>database.properties</propertyfile>
                    </componentProperties>
                    <components>
                        <component>
                            <name>hbm2ddl</name>
                            <implementation>annotationconfiguration</implementation>
                        </component>
                    </components>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>postgresql</groupId>
                        <artifactId>postgresql</artifactId>
                        <version>8.2-507.jdbc3</version>
                    </dependency>
                </dependencies>
            </plugin>

굵은 글씨 부분은 사용하시는 프로젝트에 맞게 변경해야 할 부분입니다.

일단, 구조를 보면 configuration에 크게 두가지가 들어있는데, 하나는 component들을 담고 있는 components이고, 다른 건 componentProperties입니다. 제가 사용하려는건 hbm2ddl이기 때문에 hbm2ddl 컴포넌트만 등록해 두었습니다. 그와 관련된 설정은 componentProperties여기에 들어있죠.

먼저, drop은 기존의 DB의 테이블 들을 깔끔하게 날려버릴 sql을 만들지 여부를 나타냅니다. 기본 값은 false기 때문에 위와 같은 설정에서는 생략해도 됩니다.

create는 뭔지 아시겠죠? 패스. 기본값은 true입니다.

format은 보기 좋은 형태로 SQL 출력 형태를 다듬어 줍니다. 기본 값은 false입니다.

export는 현재 DB에 적용을 할꺼냐는 건데.. 위험하기 때문에 일단은 false가 좋겠습니다. 그런데 기본값은 true입니다. 하지만, DB 마이그레이션 자동화가 되어있다면 true로 놓고 매번 DB 스키마를 새롭게 업데이트 한 다음 백업했던 데이터를 채워주면 되겠습니다.

jdk5는 역시 패스. 기본값은 false입니다.

outputfilename는 ddl을 출력할 파일 이름인데, 이 파일은 프로젝트/target/hibernate3/sql 밑에 생깁니다.

configurationfile는 하이버네이트 설정 파일 위치를 알려줍니다.

propertyfile는 하이버네이트가 DB에 접근할 때 필요한 프로퍼티를 가지고 있는 파일 위치를 알려줍니다.

2. 하이버네이트 설정 파일 만들기

<!DOCTYPE hibernate-configuration SYSTEM
“http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd”>

<hibernate-configuration>
    <session-factory>
        <mapping class=”springsprout.domain.Member” />
        <mapping class=”springsprout.domain.Comment” />
        <mapping class=”springsprout.domain.Resource” />
        <mapping class=”springsprout.domain.Right” />
        <mapping class=”springsprout.domain.Role” />
        <mapping class=”springsprout.domain.wiki.Histories” />
        <mapping class=”springsprout.domain.wiki.History” />
        <mapping class=”springsprout.domain.wiki.WikiDocument” />
        <mapping class=”springsprout.domain.study.Study” />
        <mapping class=”springsprout.domain.study.Presentation” />
        <mapping class=”springsprout.domain.study.Meeting” />
        <mapping class=”springsprout.domain.study.Attendance” />
        <mapping class=”springsprout.domain.seminar.Seminar” />
        <mapping class=”springsprout.domain.seminar.SeminarComer” />
        <mapping class=”springsprout.domain.notice.Notice” />
        <mapping class=”springsprout.domain.main.Graffiti” />
        <mapping class=”springsprout.domain.file.UploadFile” />
    </session-factory>
</hibernate-configuration>

애노테이션기반으로 설정한 경우에는 위와 같이 애노테이션으로 맵핑한 클래스들을 알려줍니다.

3. 하이버네이트 프로퍼티 추가하기

hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
hibernate.connection.username=***
hibernate.connection.password=***
hibernate.connection.driver_class=org.postgresql.Driver
hibernate.connection.url=***

이런 설정을 프로퍼티 파일에 추가하거나 새로운 프로퍼티 파일을 만들어서 추가해줍니다.

끝!!!

이제 hbm2ddl 골을 실행할 수 있습니다.

제가 원한건 새로운 스키마용 ddl이 아니라, 기본 DB에서 수정할 것들만 알려주는 수정용 ddl인데 어떻게 설정해야 되는지 잘 모르겠군요. 그런 기능을 지원해주는 건지 아닌지도 몰겠고.. componentProperties를 보면 update 속성이 있긴한데, 이 녀석에 true를 줘버리면 ddl 자체가 안 만들어집니다. @_@;;

[하이버네이트] 컬럼 타입은 어떻게 명시하는게 좋을까?

       @Column(columnDefinition=”TEXT”)

       private String descr;

이런 방법이 있습니다. 별로 좋은 방법은 아닙니다. postgresql에서는 괜찮지만, HSQL에서는 저 TEXT라는 SQL 타입이  못해서 해당 테이블을 만들지 못할겁니다.

columnDefinition 이 속성 자체가 컬럼 만들 때 사용할 SQL을 입력하는 부분이기 때문에, 각기 다른 밴더 DB에서 못 인식하는 경우도 생길 수 있는거죠.

그래서 타입을 선언하고 싶을 때는 하이버네이트 타입을 선언할 수 있는 @Type을 사용하는 것이 좋겠습니다. 그러면 하이버네이트가 컬럼을 만들 때 @Type에 선언된 하이버네이트 타입을 보고 DB에 적당한 SQL을 이용해서 컬럼을 만들어 줄 것이기 때문이죠.

    @Column
    @Type(type = “text”)
    private String descr;

그래서, 이렇게 하는게 좋겠습니다.

[봄싹 버그]] JSON 뷰와 하이버가 가져온 Proxy 객체

JSON뷰랑 하이버 Proxy 객체가 만나면 JSON 뷰를 만들다 에러가 납니다.

하이버 객체가 Lazy 로딩을 할 수 없는 지점에서 Proxy 객체를 통해 collection에 접근해서 JSON 뷰로 만들 수 없는 데이터에 접근하여 발생하는 에러로 추측하고 있습니다. 에러가 좀 깔끔하게 떨어지면 해결책이나 원인을 찾기도 쉬울텐데.. 이건 뭐.. StackOverFlow 입니다. Q&A 게시판이 아니라. 정말 그 에러입니다.

이런 일이 발생한 대표적인 시나리오는 현재까지 세 군대 정도 됩니다.
– 로그인
– 출석체크
– 낙서장

이중에서 출석체크와 낙서장은 제가 해결했는데 그 방법이 비슷하지만 살짝 다릅니다.

먼저, 출첵의 경우 proxy객체를 직렬화 하는데, 필요 없는 객체를 JSON 뷰로 넘기고 있었습니다. @SessionAttribute에 등록한 객체들이 Model model 객체에 기본으로 들어가 있었고, 그 객체들(study, member, meeting)을 JSON 뷰로 직렬화 하다가 에러가 났습니다. 그래서 Model model을 깨끗하게 비워버리고 JSON 뷰로 넘겨주도록 헬퍼를 만들어 사용했습니다.

    @RequestMapping(“/study/{studyId}/meeting/{meetingId}/confirm/{attendanceId}”)
    public ModelAndView confirmMember(Model model, @PathVariable int studyId,
            @PathVariable int meetingId, @PathVariable int attendanceId,
            HttpSession session) {
        service.confirmAttendanceById(attendanceId);
        return JsonHelper.jsonViewWithCleanMap(model);
    }

두 번째 낙서장은 제가 맡은 부분은 아닌데, 계속 눈에 걸려서… 암튼 보니까 필요한건 Grafitty의 comments 뿐인데, Graffiy의 작성자(Member)를 포함한 모든 속성들을 다 가져오더군요. 그래서 JSON 뷰에서는 또 타고 타고 들어가다가 접근 못하는 부분(아마도 Member가 들고 있는 Set<Role> 타입의 프로퍼티)에서 JSON 뷰를 만들다 직렬화 에러를 냈을 겁니다. 이번에는 DAO에서 하이버네이트의 Projection을 이용해서 필요한 것만 가져오도록 쿼리를 수정해서 처리했습니다.

    @SuppressWarnings(“unchecked”)
    public List<Graffiti> getByWriteDate(Date writeDate) throws DataAccessException {
        Criteria c = getCurrentSession().createCriteria(Graffiti.class)
            .add(Expression.ge(“writeDate”, writeDate))
            .addOrder(Order.asc(“writeDate”))
            .setProjection(Property.forName(“contents”));
        return c.list();
    }

    @SuppressWarnings(“unchecked”)
    public List<Graffiti> getRecent10Contents() {
        Criteria c = getCurrentSession().createCriteria(Graffiti.class)
            .setMaxResults(10)
            .addOrder(Order.asc(“writeDate”))
            .setProjection(Property.forName(“contents”));
        return c.list();
    }

이 방법들은 완전한 대책이 아니라, 적당히 필요한 데이터만 간추리다보니 해결이 된겁니다. 땜빵이라고 하기도 좀 뭐하지만.. 해결책이라고 하기도 좀 뭐하지요.

좀 더 궁극적인 해결책을 생각해 봤는데;;

OSIV Fileter가 MappingJacksonJsonView와 뭔가 잘 안 맞는것 같습니다. JSON이 빌드할 때도 트랜잭션 경계 안에 들어있는 상태라면 하이버 프록시 객체에서 타고 타고 타고 들어갈 수 있는건데… 그게 안 되서 에러가 나는 거겠죠?? 결국은 AOP로 MappingJacksonJsonView의 특정 메서드를 실행하기 전에 트랜잭션을 열고.. 작업을 끝낸다음 트랜잭션을 닫는 작업을 해줘야 하는거 아닌지.. 고민입니다.

아이고;; 번역 헀어야 하는데.. 봄싹에 손을 대버리다니… 큰일이네… 큰일이야.. 에휴… 봄싹 중독인가. @_@

[작명 고민] 하이버네이트 get/find류 작명 규약 1

참조: http://blog.xebia.com/2009/04/03/jpa-implementation-patterns-retrieving-entities/

아시다시피, 하이버네이트에서 영속화 중인 객체를 가져오는 방법은 get()과 load()가 있습니다. 둘 다 가져올 객체 클래스와 id 값을 넘겨주면 원하는 객체를 가져올 수 있습니다.

일단 중요한 차이점 하나는 가져다 달라고 하는 객체가 없을 때 get()은 null을 반환하고 load()는 ObjectNotFountException을 던진다는 것입니다. 또, get()은 항상 DB에서 꺼내오게 쿼리가 날아가며 load()는 프록시를 반환한 뒤 실제로 객체의 다른 속성 값들이 필요할 때 쿼리가 날아가도록 Lazy loading을 활용할 수 있습니다.

그러나 여기서 말하려는건 get, load가 아니라 Session.createQuery() 또는 createCriteria()를 이용해서 만드는 DAO의 메서드 작명 지침과 그 규약에 대한 것입니다.

DAO를 만들다 보면, 검색 류의 메서드들을 많이 추가하게 되는데, 그 이름을 지을 때마다 get으로 할까 find로 할까 by 뒤에 매개변수 타입을 적어줄까 아니면 어차피 메서드 매개변수에 있으니까 생략할까.. 이런 고민을 하게 되는데 맨 위 참조 글을 적은 분이 잘 정리해 두셨더군요.

위 글을 적으신 분은 EntityManager API의 find() 메서드와 createQuery() 메서드에 따라 규약을 만들었더군요. 그것을 응용해서 Session API의 createQuery(), createSqlQuery(), createCriteria(), get(), load() 등을 사용하는 DAO의 메서드 이름과 그 동작방식에 대한 규약을 정할 수 있을 것 같습니다.

그래야만 아래처럼 애매한 이름의 DAO 메서드들이 만들어 지지 않을테니까요.


여러 Study 객체를 가져오는데, 어떤 것은 getStudyList 어떤 것은 findXXXStudies 라니..
– get과 find의 구분도 없고
– Study 복수형을 쓸지 List를 붙일지 규약도 없네요.
– 그리고 무엇으로 검색을 한다는 것도 추측이 안 되고 말이죠.

그리고 하나 더 Finder를 제공해주는 AridPOJOs라는 걸 사부님 블로그에서 얼핏 봤었는데 자세히 좀 살펴보고 싶어지는군요. Finder까지 기본 제공해주는 GenericDao!! 멋지자나요. 이미 AridPOJOs에서는 Finder를 만들면서 위와 같은 고민을 했었겠죠?

흠… 생각 좀 해봐야겠습니다.