by 크캬캬

하이버네이트 팁
#

원문 : http://www.theserverside.com/news/thread.tss?thread_id=32082

내가 알고 있는 몇몇 사람들은 그들의 (매우 큰 규모의) J2EE 어플리케이션을, 엔터티빈에 CMP(without CMR)를 더하여 토착의(homegrown) OR 프레임워크를 사용하는 것으로부터 하이버네이트로 옮길 것을 진지하게 고려하고 있다. 그리고 그들은 나에게 약간의 팁을 요청했다. 나는 하이버네이트 전문가가 아니지만, 엔터프라이즈 제품에서 그것을 사용해 본 바가 있고, 특징들을 더했으며, 패치를 승인했었다. 어쨌건간에 이것에 대해 써왔기 때문에 내가 예전에 블로그했던 것들을 떠올려 보았다.

  1. 최신판을 사용하라. 비록 지금은 베타버전이기는 하지만(역자주:현재는 rc 버전이다.) 하이버네이트 3로 건너뛸 것을 제안하는데, 왜냐하면 매우 유용한 새로운 특징들을 가지고 있기 때문이다.
  2. 모든 관계를 lazy(하이버네이트 3에서는 디폴트이다.)로 만들고, eagerly 조인 혹은 데이터 fetch 는 특정한 유스 케이스에서만 의식적인 선택사항으로 해야 한다.
  3. 당신의 세션관리 전략을 빨리 결정해야 한다. 하나의 request 당 한 세션을 둘 것인가, 분리된 객체를 가진 request 당 세션을 둘 것인가, 다수의 request을 교차하는 "어플리케이션 트랜잭션" 당 세션을 둘 것인가 등을 말이다. 이것이 클라이언트-서버 어플리케이션에서 어떻게 동작할 것인지에 대해서는 확신하지 마라. 이것은 상당부분 웹 어플리케이션 관점으로부터 나온 것이다.
  4. flush 전략을 빨리 수립하라 : 하이버네이트 auto-flush에 맡겨두던가, 데이터베이스에 flush 할 당신 자신의 동기화 지점을 정의하라.
  5. 당신의 캐쉬 전략을 빨리 정의하라 : transactional 데이터를 캐쉬할 것인가? 만약 그렇다면, www.tangosol.com 로 가서 그들의 제품, Coherence를 사라. 만약 당신이 단지 모든 클러스터 멤버들에 대한 유효한 변화들 사이의 다소 작은 시간지연 현상이 있는 부분에서 lookup/setup 데이터만을 캐쉬할 생각이라면, 당신은 OSCache 와 같은 오픈소스만으로도 충분할 것이다. transactional 캐쉬는 매우 선호되는데, 이것은 당신으로 하여금 캐쉬가 가진 엄청난 파워라고 할 수 있는 쿼리 캐쉬를 사용할 수 있게 해준다. 나는 non-transactional 캐쉬를 쿼리 캐쉬의 목적으로 사용하는 사람들과 말을 해 본 적이 있는데, 하이버네이트 문서와 Gavin 은 그런 방법이 안전하지 못하다고 말한다. 그것은 아마도 99.9%의 시간동안 작동할 것이지만, 그러나...(역자주:0.1%의 불안함이 있다는 듯?) 쿼리 캐쉬는 비록 transactional 캐쉬가 없이 non-transactional 데이타에 대한 쿼리들만 캐쉬하더라도 유용할 것이다.
  6. 당신의 엔터티들을 캐쉬하라, 그리고 그 캐쉬 세팅들을 연관된 매핑들(set, map, bag, list)에 잘 적용하는지를 확인하라.
  7. 당신은 엔터티를 오로지 그것의 일대다 혹은 다대다 관계에 있는 것과 조인할 수 있다. 때문에 올바른 것을 선택해야만 한다. 당신이 eagerly 로드하기를 원하는 다른 컬렉션들의 배치 사이즈(한 번에 가져올 연관된 레코드들의 숫자)에 대한 적절한 값을 세팅하라.
  8. 당신의 엔터티들에 대한 레퍼런스들이 어디에서도 가비지 컬렉션을 방해하고 있지 않음을 확신하기 위해 object 그래프를 검사하라. 이것은 많은 관계를 가지고 자주 변경되는 엔터티들에게는 정말로 중요한데, 왜냐하면 메모리를 채워버릴 많은 objects가 있기 때문이다.
  9. 만일 가능하다면, 버전 컬럼을 가지고 있는 optimistic concurrency를 사용하라. Timestamps 역시 동일한 방식으로 작용하지만, 깔끔하진 않다. 하이버네이트가 레코드 변경여부를 확인하기 위해 모든 값을 검사하도록 해선 안된다.
  10. identifier 생성의 생명주기를 이해해야 한다. 만약 당신이 시퀀스나 다른 데이터베이스 생성 identifier 를 사용한다면, 당신의 identifier 는 새로운 엔터티가 데이터베이스에 저장될 때까지 부여되지 않을 것이다. 만약 당신이 identifier를 당신의 equals() 와 hashCode() 구현체의 일부분으로 사용한다면, 만약 당신이 엔터티를 저장하기 전에 Set 에 담는다면 당신은 저장된 후에 다시 찾을 수 없을 것이다. 나는 이러한 이유에서 엔터티 인스턴스의 생성자에서 할당된 UUIDs 를 사용해왔으며 그것은 삶을 좀 더 쉽게 만들어주었다. 나는 이러한 문제에 직면한 몇몇 사람들에 대해 얘기 들어왔는데, hashCode() 구현이 엔터티의 모든 인스턴스에 대해 똑같은 숫자값을 항상 반환한다는 것이었다. 기술적으로 hashCode()를 실행하는 동안은 이것은 결코 최적이 될 수 없다.
  11. 하이버네이트를 trace할 수 있도록, 당신의 IDE 에 당신이 사용하고 있는 배포판에 들어 있는 하이버네이트 소스 코드에 대한 참조를 세팅하라. 이것은 당신이 보고 있는 동작을 유발하는 것에 대한 이해를 도와줄 뿐 아니라, 당신이 하이버네이트가 어떻게 동작하는지에 대해서 이해할 수 있도록 해준다.
  12. 두번째 레벨 캐쉬에 대해 이해하라. (그리고 세션은 당신의 첫번째 레벨 캐쉬에 있음을 이해하라.) 이것이 당신의 엔터티 데이터를 캐쉬하는 방법(field 값들의 배열에 대한 identifier의 맵 형식)과 컬렉션들(이것은 단지 identifiers를 저장하고 엔터티 캐쉬로부터 객체들을 새로 구성한다.)에 대해 이해하라.
  13. Hibernate in Action 을 가서 사도록 하라. 이 책은 하이버네이트 2.1 을 다루고 있지만 기본적인 개념은 같으며 3.0 에서는 몇가지 새로운 특징들이 추가되었다.
  14. 새로운 특징들을 말해보자면, 필터를 살펴보도록 하라. 나는 이전에 필터를 사용할 기회가 없었는데, 그것들이 유효 날짜 문제(effective date problem)를 매우 쉽게 만든다는 단순한 사실이 굉장한 이점(huge win)을 가져다 주었다. 필터는 전체를 로드하지 않고도 당신이 컬렉션 같은 것에서 많은 레코드들을 찾을 수 있게 해준다. 굿이다.
  15. 이제 시작하기 위해 당신의 첫번째 할 일은 메모리와 CPU 프로파일러와 IronTrack SQL 과 같은 SQL 프로파일러 역시 설치하는 것이다. 그리고, 모든 설정들을 꼬아놓고 프로파일러를 사용하면서 당신의 테스트 케이스들을 새로 동작시키고 어떤 효과가 있는지 지켜보도록 하라.

원문 : #


Hibernate Tips

Some people I know are looking at porting their (very large) J2EE application from using a homegrown OR framework on top of Entity Beans with CMP (without CMR) to Hibernate, and they asked me for some tips. I'm not claiming to be a Hibernate expert, but I've used it on an enterprise product, added features, submitted patches, etc. so I know a bit. Since I was writing this up anyway, I figured I'd blog it.

  1. Use the latest. I would suggest jumping on Hibernate 3 even though it's in beta now as it has a lot of very useful new features.
  2. Make all associations lazy (Hibernate 3 makes this the default) and make it a concious choice to eagerly join or fetch data for specific use-cases.
  3. Define your Session management strategy early. Will it be one session per request, session per request with detached objects, session per "application transaction" across multiple requests, etc. Not sure how this would play in a client-server app. This is more from a web application perspective.
  4. Define the flush strategy early : let Hibernate auto-flush vs. defining your own synchronization points where you flush to the database.
  5. Define your caching strategy early: will you cache transactional data? If so go to www.tangosol.com and talk to them about buying their product, Coherence. If you are only caching lookup / setup data where some small time-lag between changes being available to all cluster members is acceptable, then you can get away with an opensource implementation like OSCache. The transactional cache is very much preferred, as it will allow you to use the query cache, which is where a lot of the power of the cache lays. I've talked to people who use non-transactional caches for the query cache, but the Hibernate docs and Gavin say that it's not safe. It will probably work 99.9% of the time, but.... The query cache could be useful for caching queries for non-transactional data even without a transactional cache.
  6. Cache your entities, and make sure to apply the cache settings to their association mappings as well (set, map, bag, list).
  7. You can only join from an entity to one of its one-to-many or many-to-many associations, so choose the right one. Set appropriate values for the batch size of the other collections (the number of related records to load at once) which you want to be eagerly loaded.
  8. Examine your object graphs to make sure that references to entities won't be held anywhere preventing garbage collection. This is especially true for entities with lots of associations and which change frequently, as you can get lots of objects filling up memory.
  9. Use optimistic concurrency with a version column if possible. Timestamps work too, but not as cleanly. Avoid making Hibernate examine all values to determine if records have changed.
  10. Understand the lifecycle of identifier creation. If you are using sequences or other database-generated identifiers, your identifiers won't be set until the new entity has been saved to the database. If you use the identifier as part of your equals() and hashCode() implementation, this means that if you add the entity to a Set before you save it, you won't be able to find it again after it's saved. I've gone to UUIDs assigned in the constructor of the entity instances for this reason, and it makes life much easier. I've heard that some people, faced with this, have made their hashCode() implementation always return the same number for every instance of an entity. While this technically fulfills the contract of hashCode() it's hardly optimal.
  11. Set your IDE up with a reference to the Hibernate source code of the distribution you are using so you can trace into it. Not only will it help you understand what's causing the behavior you're seeing, but it will help you understand how Hibernate works.
  12. Understand the 2nd level cache (and understand that the Session is your 1st level cache). Understand how it caches your entity data (as a Map of identifier to Array of field values) and collections (it just saves the identifiers and re-constitutes the objects from the entity cache).
  13. Go buy Hibernate in Action. It covers Hibernate 2.1 but the ideas are the same, there are just some new features in 3.0.
  14. Speaking of new features, look at Filters. I haven't had a chance to use them yet, but the mere fact that they make the effective date problem so easy makes them a huge win. They can also let you find the number of records in a collection, etc. without having to load the whole thing, very nice.
  15. Baseline your first working setup with memory and CPU profilers and also with a SQL profiler like IronTrack SQL, then re-run your test cases with the profilers for every configuration tweak to see what the effects are.

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-1) was last changed on 06-Apr-2006 09:45 by UnknownAuthor