이 기사에서는 최대 절전 모드 대기 시간 로딩 기술에 대해 설명합니다. 다음과 같이 참조에 대해 공유하십시오.
Hibernae의 게으른 적재는 매우 일반적인 기술입니다. 엔티티의 수집 속성은 기본적으로 지연되며 엔티티와 관련된 엔티티도 기본적으로 지연됩니다. Hibernate는이 지연된 하중을 사용하여 시스템의 메모리 오버 헤드를 줄여 최대 절전 모드의 작동 성능을 보장합니다.
먼저 최대 절전 모드 지연 하중의 "비밀"을 분석하겠습니다.
수집 특성의 게으른 부하
최대 절전 모드가 데이터베이스에서 지속적인 엔티티를 초기화 할 때 해당 엔티티의 수집 속성이 영구 클래스로 초기화 되었습니까? 컬렉션 속성에 100,000 또는 수백만의 레코드가 포함 된 경우, 지속적인 엔티티를 초기화하면서 모든 컬렉션 속성의 크롤링으로 인해 성능이 급격히 감소합니다. 시스템이 영구 클래스의 컬렉션 속성에서 일부 레코드 만 사용하면 전적으로 컬렉션 속성이 아닙니다. 이런 식으로, 모든 컬렉션 속성을 한 번에로드 할 필요가 없습니다.
게으른 로딩 전략은 일반적으로 수집 특성에 권장됩니다. 소위 지연로드는 시스템이 수집 속성을 사용해야 할 때 데이터베이스의 관련 데이터를로드하는 것입니다.
예를 들어, 다음 사람 클래스는 컬렉션 속성을 보유하고 있으며 컬렉션 속성의 요소에는 유형 주소가 있고 개인 클래스의 코드 스 니펫은 다음과 같습니다.
Listing 1. person.java
공개 클래스 사람 {// 속성 개인 정수 ID를 식별합니다. // 사람의 이름 속성 개인 문자열 이름; // 사람의 연령 속성을 개인 int 연령; // 수집 속성 속성을 저장하기 위해 세트를 사용하여 개인 세트 <desssude> 주소 = new Hashset <dassching> (); // 각 속성의 세터 및 getter 메소드는 아래에서 생략됩니다 ...}최대 절전 모드가 영구 클래스의 컬렉션 속성을 관리하기 위해 프로그램은 영구 클래스에 대한 다음 매핑 파일을 제공합니다.
Listing 2. person.hbm.xml
<? xml version = "1.0"alcoding = "gbk"?> <! doctype hibernate-mapping public "-// hibernate/hibernate 매핑 dtd 3.0 // en" "http://www.hibernate.org/dtdd/hibernate-mapping-3.0.dtd"> Hibernate-mappe package = "org.crazyit.app.apt.domain"> <!--맵핑 개인 지속성 클래스-> <class name = "person"table = "person_inf"> <!-맵핑 식별 속성 ID-> <id name = "id"열 = "person_id"> <!-정의 기본 키 생성 정책-> <generatator/> <!-<property name = "" ""> 이름 = "age"type = "int"/> <!-맵 컬렉션 속성-> <set name = "address"table = "person_address"lazy = "true"> <!-관련 외국 키 열 = "key column ="person_id "/> <composite-element> <!-<속성 이름 ="세부 사항 "! 이름 = "zip"/> </composite-element> </set> </class> </hibernate-mapping>
파일을 맵핑하는 위의 코드에서 Person의 수집 속성의 주소 클래스가 정상적인 pojo라는 것을 알 수 있습니다. 주소 클래스에는 세부 사항과 zip의 두 가지 속성이 포함되어 있습니다. 주소 클래스 코드는 매우 간단하기 때문에이 클래스의 코드는 더 이상 여기에 제공되지 않습니다.
위의 매핑 파일의 <set .../> 요소의 코드는 Lazy = "true"(<set .../> element, lazy = "true"에 대해 "true"를 지정합니다.
예를 들어, 다음 코드를 따라 ID 1이있는 사람 엔티티를로드하십시오.
세션 세션 = sf.getCurrentSess (); 트랜잭션 tx = session.beginTransaction (); person p = (person) session.get (person.class, 1); // <1> system.out.println (p.getName ());
위의 코드는 ID 1이있는 사람 엔티티에 액세스하기 만하면이 개인 엔티티와 관련된 주소 오브젝트에 액세스하고 싶지 않습니다. 현재 두 가지 상황이 있습니다.
1.로드가 지연되지 않으면 최대 절전 모드는 개인 엔티티에 해당하는 데이터 레코드를로드 할 때 개인 엔티티와 관련된 주소 개체를 즉시 가져옵니다.
2. 게으른 하중을 사용하는 경우 최대 절전 모드는 개인 엔티티에 해당하는 데이터 레코드 만로드합니다.
두 번째 접근 방식은 데이터베이스와의 상호 작용을 줄일뿐만 아니라 주소 엔티티로드로 인한 메모리 오버 헤드를 피할 수 있습니다. 또한 최대 절전 모드가 기본적으로 게으른로드를 가능하게하는 이유입니다.
문제는 이제 게으른 하중이 어떻게 구현됩니까? 최대 학부를로드 할 때 개인 실체의 주소 값은 무엇입니까?
이 문제를 해결하기 위해 코드 <1>에서 중단 점을 설정하고 Eclipse에서 디버깅합니다. 현재 Eclipse 콘솔 창에 그림 1과 같이 출력이 있음을 알 수 있습니다.
그림 1. 게으른 하중 수집 특성에 대한 콘솔 출력
그림 1의 출력에 표시된 바와 같이, 최대 절전 모드는 개인 엔티티에 해당하는 데이터 테이블에서 데이터를 가져 오며 주소 개체에 해당하는 데이터 테이블에서 데이터를 가져 가지 않습니다. 이것은 게으른 하중입니다.
그렇다면 개인 실체의 주소 재산은 무엇입니까? 현재 Eclipse의 변수 창에서 그림 2에 표시된 결과를 볼 수 있습니다.
그림 2. 게으른로드 된 수집 속성 값
그림 2의 상자에있는 내용에서 주소 속성은 해시 세트 및 트리셋과 같은 친숙한 구현 클래스가 아니라 세트 인터페이스를 위해 최대 절전 모드에서 제공하는 구현 클래스 인 PersistentSet 구현 클래스라는 것을 알 수 있습니다.
PersistentSet Collection 객체는 실제로 기본 데이터 테이블의 데이터를 캡처하지 않으므로 컬렉션의 주소 객체를 실제로 초기화하는 것은 자연스럽게 불가능합니다. 그러나 PersistentSet Collection에는 최대 절전 모드 세션 인 세션 속성이 있습니다. 프로그램이 PersistentSet Collection 요소에 액세스 해야하는 경우 PersistEntSet 은이 세션 속성을 사용하여 실제 주소 개체에 해당하는 데이터 레코드를 잡습니다.
그렇다면 해당 주소 엔티티에 해당하는 데이터 레코드를 정확히 무엇을 가져 오나요? PersistentSet Collection에 소유자 속성이 있기 때문에 PersistentSet에게는 어렵지 않습니다. Hibernate는 데이터 테이블에 해당하는 주소에 해당하는 데이터 테이블의 데이터를 검색합니다.
예를 들어, 그림 2에 표시된 창의 주소 선을 클릭합니다. 즉, Eclipse에 주소 속성을 디버그하고 출력하도록 지시합니다. 주소 속성에 액세스하는 것입니다. 현재 Eclipse 콘솔 창에서 다음 SQL 문을 볼 수 있습니다.
주소를 선택하십시오.
이것은 소유자 속성에 따라 특정 주소 레코드를 캡처하는 PersistentSet Collection 및 SQL 문입니다. 현재 Eclipse의 변수 창에서 그림 3에 표시된 출력을 볼 수 있습니다.
그림 3.로드 된 수집 속성 값
그림 3에서 알 수 있듯이, 현재 주소 속성이 초기화되었으며, 세트에는 2 개의 주소 개체가 포함되어 있으며, 여기에는 개인 엔티티와 관련된 두 개의 주소 개체입니다.
위의 소개에서, 우리는 최대 절전 모드의 세트 속성을 지연시키는 키가 PersistentSet 구현 클래스에 있음을 알 수 있습니다. 게으른 로딩 중에 PersistentSet 컬렉션에는 요소가 없습니다. 그러나 PersistentSet은 최대 절전 모드 세션을 개최하여 프로그램이 컬렉션에 액세스해야 할 때 데이터 레코드가 "즉시"로드되어 수집 요소를로드 할 수 있습니다.
PersistentSet 구현 클래스와 유사하게 Hibernate는 PersistentList, PersistentMap, PersistentSortedMap, PersistentSortedSet 및 기타 구현 클래스를 제공하며 해당 기능은 PersistentSet의 기능과 거의 유사합니다.
최대 절전 모드 컬렉션 속성에 익숙한 독자는 다음을 기억해야합니다. 최대 절전 모드는 선언 컬렉션 속성을 세트, 목록, 맵, SortedSet, SortedMap 등과 같은 인터페이스에서만 사용할 수 있으며 Hashset, Arraylist, Hashmap, TreeSet, Treemap 및 기타 구현 클래스를 사용하여 구현할 수 없습니다. hibernate는 컬렉션 속성을 지연시켜야하고 최대 절전 모드 지연이 PersistentSet, PersistentList, PersistentList, PersistentList, PersistentStortedMap 및 PeristentSortedSet에 의존하여 자체 컬렉션을 사용하여 컬렉션을 완료하기 위해 컬렉션을 이용해야하는 것이 아니라 컬렉션을 사용하여 개발자가 필요합니다. 속성.
최대 절전 모드는 기본적으로 수집 속성을 위해 게으른로드를 사용합니다. 일부 특별한 경우에는 <set .../>, <list .../>, <map .../>와 같은 요소에 대한 Lazy = "False"속성을 설정하여 게으른로드를 취소하십시오.
관련 엔티티의로드 지연
기본적으로 최대 절전 모드는 게으른 하중을 사용하여 관련 엔티티를로드합니다. 일대일 협회, 일대일 협회 또는 다수의 협회이든, 최대 절전 모드는 기본적으로 게으른로드를 사용합니다.
관련 실체의 경우 두 가지 경우로 나눌 수 있습니다.
1. 관련 엔티티가 다수의 엔티티 (일대일, 다수의 마니 포함) 일 때 :이 시점에서 관련 엔티티는 컬렉션 형태로 존재하며 Hibernate는 PersistentSet, PersistentList, PersistentList, PersistentSortedMap, PersistentSortedSet 및 기타로드 엔티티를 관리합니다. 이것은 앞에서 도입 된 상황입니다.
2. 관련 엔티티가 단일 엔티티 (일대일 및 다수 포함) 일 때 : 최대 절전 모드가 엔티티를로드하면 지연된 관련 엔티티는 동적으로 생성 된 프록시 객체가됩니다.
관련 엔티티가 단일 엔티티 인 경우, 즉 관련 엔티티가 <lever-one .../> 또는 <일대일 .../>를 사용하여 매핑 될 때,이 두 요소는 게으른 속성을 통해 게으른 하중을 지정할 수 있습니다.
다음 예제는 주소 클래스를 영구 클래스에 매핑합니다. 현재 주소 클래스는 엔티티 클래스가되고 개인 엔티티와 주소 엔티티는 일대일 양방향 협회를 형성합니다. 현재 매핑 파일 코드는 다음과 같습니다.
목록 3. person.hbm.xml
<? xml version = "1.0"encoding = "gbk"?> <!-최대 절전 모드의 DTD 정보를 지정합니다-> <! doctype hibernate 맵핑 공개 "-// hibernate/hibernate 매핑 dtd 3.0 // en "" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping package = "org.crazyit.app.domain"> <!-맵핑 사람의 지속성 클래스-> <class name = "person_inf">-<id name = "id id. column = "person_id"> <!-기본 키 생성기 정책 정의-> <generator/> <!-공통 속성을 매핑하는 데 사용되는 generator/> <!-"string"/<property name = "age"type = "int"/<!-맵 컬렉션 속성, 컬렉션 요소가 Cascade 속성을 지정하지 않는 또 다른 지속적인 엔티티입니다. inverse = "true"> <!-관련 외국 키 열을 지정합니다-> <key column = "person_id"/> <!-관련 클래스 속성에 맵핑하는 데 사용됩니다-> <one-to-many/> </set> </class> <!-지도 주소 끊임없는 클래스-> <class name = "address" "jand 기본 키 생성기 정책을 지정-> <generator/> </id> <!-맵 정상 속성 세부 사항-> <속성 이름 = "세부 사항"/> <!-지도 정상 속성 zip-> <속성 이름 = "zip"/> <!-열 이름은 person_id로 지정되어야합니다. NOT-NULL = "True"/> </class> </hibernate-mapping>
다음으로, 프로그램은 다음 코드 스 니펫을 통해 ID 1과 함께 개인 엔티티를로드합니다.
// 컨텍스트-의존적 세션 세션 세션을 엽니 다. // <1> system.out.println (address.getDetail ());
주소 엔티티를로드 할 때 최대 절전 모드의 관련 엔티티의 처리를보기 위해 코드 <1>에서 중단 점을 설정하여 Eclipse에서 디버깅합니다. 현재 Eclipse Console Window가 다음 SQL 문을 출력한다는 것을 알 수 있습니다.
주소 1_1_0_, address0_.detail as avertion1_0_, jands.0_.zip as zip1_0_, juster0_.person_id as address_inf jand
이 SQL 문에서 최대 절전 모드가 주소 엔티티에 해당하는 데이터 테이블을 크롤링 레코드에로드하지만 개인 엔터티에 해당하는 데이터 테이블에서 레코드를 크롤링하지 않는다는 것을 알기가 어렵지 않습니다. 이는 게으른로드가 역할을한다는 것입니다.
Eclipse의 변수 창에서 그림 4에 표시된 출력을 참조하십시오.
그림 4. 지연된 로딩 엔티티
주소 엔티티와 관련된 개인 실체는 개인 대상이 아니라 사람의 인스턴스 _ $$ _ javassist_0 클래스임을 명확하게 볼 수 있습니다. 이 클래스는 Javassist 프로젝트를 사용하여 Hibernate에 의해 동적으로 생성 된 프록시 클래스입니다. 최대 절전 모드 지연이 관련 엔티티를로드하면 Javassist는 동적 프록시 객체를 생성하는 데 사용 되며이 프록시 객체는 "아직로드되지 않은"을 프록시 할 책임이 있습니다.
응용 프로그램이 "아직로드되지 않은"관련 엔티티를 사용해야하는 한, _ $$ _ javassist_0 프록시 객체는 실제 관련 엔티티를로드하고 실제 관련 엔티티를 반환하는 데 책임이 있습니다. 이것은 가장 일반적인 프록시 패턴입니다.
그림 4에 표시된 변수 창에서 사람 속성을 클릭하십시오 (즉, 개인 속성이 디버그 모드에서 사용하도록 강제로 표시하면 Eclipse의 콘솔 창에 다음 SQL 문이 나타납니다.
person0_.person_id를 person.1_0_0_, person0_.name as name0_0_, person0_.
위의 SQL 문은 "지연로드"의 관련 엔티티를 캡처하는 문입니다. 현재 변수 창 출력의 그림 5에 표시된 결과를 볼 수 있습니다.
그림 5.로드 된 엔티티
Hibernate는 관련 엔티티를 관리하기 위해 "지연로드"모드를 채택합니다. 실제로, 주 엔티티를로드 할 때, 그것은 실제로 관련 엔티티의 해당 데이터를 가져 오지 않고 관련 엔티티의 프록시로 객체를 동적으로 생성합니다. 응용 프로그램이 실제로 관련 엔티티를 사용해야하는 경우 프록시 객체는 기본 데이터베이스에서 레코드를 잡고 실제 관련 엔티티를 초기화 할 책임이 있습니다.
최대 절전 모드 지연 로딩에서 클라이언트 프로그램이 시작하는 것은 동적으로 생성 된 프록시 객체이며, 실제 엔티티는 관리를 위해 프록시 객체로 위임됩니다. 이것은 일반적인 프록시 패턴입니다.
에이전트 모드
프록시 모드는 매우 넓은 응용 프로그램이있는 설계 모드입니다. 클라이언트 코드가 객체를 호출 해야하는 경우 클라이언트는 실제로 객체를 정확하게 가져올지 여부를 신경 쓰지 않습니다. 함수를 제공 할 수있는 객체 만 있으면됩니다. 현재, 우리는 객체의 프록시 (프록시)를 반환 할 수 있습니다.
이 설계 방법에서 시스템은 프록시 객체가있는 객체를 제공하고 프록시 객체는 소스 객체에 대한 참조를 제어합니다. 프록시는 다른 Java 객체를 대신하여 작용하는 Java 객체입니다. 경우에 따라 클라이언트 코드는 Callee를 원하거나 직접 호출 할 수 없으며 프록시 객체는 클라이언트와 대상 객체 사이의 중개자 역할을 할 수 있습니다.
클라이언트의 경우 프록시 객체와 실제 객체의 차이를 구별 할 수 없으며 프록시 객체와 실제 객체의 차이를 구별 할 필요도 없습니다. 클라이언트 코드는 실제 프록시 객체를 모릅니다. 클라이언트 코드는 인터페이스 지향적이며 프록시 오브젝트의 인터페이스 만 보유합니다.
요컨대, 클라이언트 코드가 호출 된 객체에 직접 액세스 할 수 없거나 원하지 않는 한,이 상황에는 높은 시스템 오버 헤드가 높은 객체를 만드는 등 여러 가지 이유가 있습니다. 또는 원격 객체의 기능이 필요를 충족시키기에 충분하지 않지만 추가 프록시 객체는 클라이언트에 사용하기 위해 만들어 져 있으므로이 설계 방법은 프로 락스 모드입니다.
다음은 간단한 프록시 모드를 보여줍니다. 이 프로그램은 먼저 큰 이미지 객체로 구현 된 인터페이스를 나타내는 이미지 인터페이스를 제공합니다. 인터페이스 코드는 다음과 같습니다.
목록 3. image.java
공개 인터페이스 이미지 {void show ();}이 인터페이스는 큰 이미지 객체를 시뮬레이션하는 구현 클래스를 제공하며 구현 클래스의 생성자는 thread.sleep () 메소드를 사용하여 3s를 일시 중지합니다. 아래는 Bigimage의 프로그램 코드입니다.
Listing 4. bigimage.java
//이 bigimage를 사용하여 큰 이미지를 시뮬레이션합니다. 공개 클래스 Bigimage immates {public bigimage () {try {// program 3s 모드 시뮬레이션 시스템 오버 헤드 스레드 (3000); System.out.println ( "이미지 로딩 ...");} catch (InterpruptedException ex) {ex.printstacktrace ();}} // 이미지 공개 void show () {system.out.println ( "실제 큰 그림 그리기")}}}}}}}}}}위의 프로그램 코드는 3S를 일시 중지하는데, 이는 Bigimage 객체를 생성하는 데 3s 시간이 걸린다는 것을 나타냅니다. 프로그램은이 지연을 사용 하여이 이미지를로드하여 발생하는 시스템 오버 헤드를 시뮬레이션합니다. 프록시 모드를 사용하지 않으면 시스템에서 BigImage가 생성 될 때 시스템은 3S 지연을 생성합니다. 이 지연을 피하기 위해이 프로그램은 Bigimage 객체에 대한 프록시 객체를 제공하며 Bigimage 클래스의 프록시 클래스는 다음과 같습니다.
Listing 5. ImageProxy.java
공개 클래스 ImageProxy는 이미지를 구현 {// 이미지 인스턴스를 프록시 객체 개인 이미지 이미지로 결합합니다. // 추상 엔티티를 사용하여 프록시 객체 public imageproxy (이미지 이미지) {this.image = image;}/*** 이미지 인터페이스를 다시 작성하는 데 사용됩니다. show () {// 프록시 오브젝트 만 제작 (image == null) {image = new bigimage ();} image.show ();}}위의 ImageProxy 프록시 클래스는 Bigimage와 동일한 show () 메소드를 구현하여 클라이언트 코드가 프록시 객체를 얻은 후 프록시 객체를 Bigimage로 사용할 수 있습니다.
제어 로직은 ImageProxy 클래스의 show () 메소드에 추가됩니다. 이 제어 로직은 프록시 Bigimage 객체가 시스템이 실제로 이미지의 show ()를 호출 할 때만 생성 될 수 있음을 제어하는 데 사용됩니다. 다음 프로그램은 Bigimage 객체를 사용해야하지만 프로그램은 BigImage 인스턴스를 직접 반환하지는 않지만 다음 프로그램과 같이 Bigimage 프록시 객체를 먼저 반환합니다.
목록 6. bigimagetest.java
public class bigimagetest {public static void main (string [] args) {long start = system.currenttimeMillis (); 프로그램은 이미지 객체를 반환합니다. 이는 bigimage image의 프록시 객체 = new imageProxy (null); System.out.println ( "이미지 개체의 시간 오버 헤드 :") - " +(System.currentmillis); 이 프로그램은 실제로 이미지 프록시의 show () 메소드가 실제로 호출 될 때 프록시 객체를 생성합니다. image.show ();}}위의 프로그램은 프로그램이 Bigimage 객체를 실제로 생성하지 않지만 이미지 프록시 프록시 객체를 가져 오기 때문에 이미지를 매우 빠르게 초기화합니다. 위의 프로그램을 실행하고 그림 6에 표시된 결과를보십시오.
그림 6. 프록시 모드를 사용한 성능 향상
그림 6에 표시된 실행 결과를 보면 독자는 프록시 모드를 사용하면 이미지 객체를 얻는 시스템 성능이 향상된다는 데 동의 할 수 있습니다. 그러나 일부 독자들은 질문을 할 수 있습니다. 프로그램이 imageproxy 객체의 show () 메소드를 호출 할 때 큰 이민 객체를 만들어야하지만 시스템 오버 헤드가 실제로 줄어들지 않았습니까? 이 시스템 오버 헤드가 지연되는 것 뿐이야?
다음 두 가지 관점 에서이 질문에 답할 수 있습니다.
Bigimage가 실제로 필요할 때까지 지연되면 이전 프로그램의 원활한 작동을 보장하고 메모리에서 Bigimage의 생존 시간을 줄여서 시스템의 메모리 오버 헤드를 거시적 관점에서 저장할 수 있습니다.
경우에 따라 프로그램이 실제로 이미지 프록시 객체의 show () 메소드를 호출하지 않을 수도 있습니다. 즉, 시스템이 큰 이민 객체를 전혀 만들 필요가 없음을 의미합니다. 이 경우 프록시 모드를 사용하면 시스템 운영 성능이 크게 향상 될 수 있습니다.
완전히 유사한 Hibernate는 프록시 모드를 사용하여 관련 엔티티를로드하는 시간을 "지연"합니다. 프로그램이 관련 엔티티에 액세스 할 필요가없는 경우 프로그램은 관련 엔티티를 크롤링하지 않습니다. 이로 인해 시스템의 메모리 오버 헤드를 저장하고 최대 절전 모드가 엔티티를로드하는 시간을 단축 할 수 있습니다.
요약
최대 절전 모드 게으른 부하는 본질적으로 프록시 모드의 적용입니다. 지난 몇 년간, 우리는 종종 프록시 모드를 사용하여 시스템 메모리 오버 헤드를 줄이고 응용 프로그램 성능을 향상 시켰습니다. Hibernate는 프록시 모드의 이러한 장점을 활용하고 Javassist 또는 CGLIB를 결합하여 프록시 객체를 동적으로 생성하여 프록시 모드에 유연성을 더합니다. Hibernate는이 사용에 새로운 이름 인 Lazy Loading을 제공합니다. 어쨌든 이러한 오픈 소스 프레임 워크의 구현을 완전히 분석하고 이해하면 클래식 디자인 모델의 장점을 더 잘 경험할 수 있습니다.
이 기사의 설명이 최대 절전 모드 프레임 워크를 기반으로 한 모든 사람의 Java 프로그래밍에 도움이되기를 바랍니다.