>  기사  >  백엔드 개발  >  로드 및 세션 시작

로드 및 세션 시작

巴扎黑
巴扎黑원래의
2016-12-20 17:13:581302검색

1. get은 지연을 지원하지 않고, 로드는 지연을 지원합니다.

2. get을 사용하여 데이터를 로드합니다. 일치하는 데이터가 없으면 null이 반환되고 로드 시 예외가 발생합니다.

3. load()를 실행할 때 먼저 현재 객체가 Session에 있는지 확인하고, 존재하지 않으면 데이터베이스에서 쿼리합니다. get()을 실행하면 현재 객체가 세션에 존재하는지 여부에 관계없이 데이터베이스에서 직접 쿼리합니다. 존재하지 않으면 null이 반환됩니다.

4. load() 메서드는 엔터티의 프록시 클래스 인스턴스를 반환할 수 있지만 get()은 항상 엔터티 클래스만 반환합니다.

예제 가져오기:

1public void testGetMethod() {
2 Session 세션 = null
3 try {
4  session = HibernateUtils.getSession(); >5  session.beginTransaction();
6   
7  //즉시 sql 쿼리를 실행하고 User 개체 c2ff0002")를 로드합니다.
9   System.out.println("user.name=" + user .getName());
10  
11   user.setName("张三");
12  session.getTransaction( ).commit(); 🎜>14  e.printStackTrace();
15  session.getTransaction().rollback();
16  }finally { >17   HibernateUtils.closeSession(session); 9행. 일치하는 레코드가 없으면 null이 반환됩니다. 5   session.beginTransaction(); 이 객체가 로드됩니다(sql 문 실행)
9   //hibernate 지연 로딩의 구현 원칙은 프록시 모드입니다
10  User user = (User)session.load(User .class, "402880d01b9bf210011b9bf2b2ff0002");
11  System.out.println("user.name=" + user.getName())
12  user.setName("lee思"); session.getTransaction().commit() ;
14  }catch(Exception e) {
15   e.printStackTrace()
16   session.getTransaction().rollback(); 🎜>19  }
20 }

PS: load는 10줄의 코드가 실행될 때 즉시 sql문이 실행되지 않았습니다. 왜냐하면 지연 로딩은 실제로 객체가 로드되는 것뿐입니다. 객체가 로드되고 sql 문이 실행될 때만 핵심은 11줄의 코드입니다. 로드 메소드의 ID가 데이터베이스 테이블과 관련되지 않은 경우 ObjectNotFoundException 예외가 발생합니다.

PS: 중단점을 설정하고 디버그를 사용하여 관련 변수 및 개체의 변경 사항을 추적할 수 있으므로 로드 및 가져오기 메서드를 명확하게 이해할 수 있습니다.

최대 절전 모드, 세션에 의해 로드된 객체는

지속적 상태: 개체는 데이터베이스 기록과 대응 관계를 설정하고 동기화를 유지합니다. 객체는 지속성 컨텍스트에 바인딩되어 있으며 이후의 모든 상태 변경 및 데이터 변경은 작업 단위에서 관리됩니다. 이것이 지속성 상태입니다. Session.load는 hibernate3.2에서 제공하는 기본 지연 로딩 방법입니다. 로드되는 것은 지속성이라고도 할 수 있는 프록시라고 생각합니다. (이렇게 이해합니다. 틀렸다면 전문가에게 수정을 요청하세요. ).





지연 로딩을 이해하는 것이 지연 로딩을 이해하는 데 도움이 됩니다.

불필요한 성능 오버헤드를 피하기 위해 지연 로딩 메커니즘이 제안되었습니다. 소위 지연 로딩은 데이터가 실제로 필요할 때만 데이터 로딩 작업이 수행되는 것을 의미합니다. Hibernate는 엔터티 객체의 지연 로딩과 컬렉션의 지연 로딩도 제공합니다. 아래에서는 이러한 유형의 지연 로딩에 대해 각각 자세히 소개합니다.

A. 엔터티 객체의 지연 로딩:

엔터티 객체에 지연 로딩을 사용하려면 아래와 같이 엔터티의 매핑 구성 파일에 해당 구성을 만들어야 합니다.



<클래스 이름=”com.neusoft.entity.User” 테이블=”user”lazy=”true”> ……





클래스의 지연 속성을 true로 설정하여 엔터티의 지연 로딩 기능을 활성화합니다. . 다음 코드를 실행하면:

User user=(User)session.load(User.class,”1”) (1)

System.out.println(user.getName ()); (2)

(1)을 실행할 때 Hibernate는 현재 일부 디버깅 도구(예: JBuilder2005의 디버그 도구)를 사용하는 경우 이를 관찰합니다. 사용자 개체의 메모리 스냅샷을 보면 이때 반환된 것이 User$EnhancerByCGLIB$$bede8986 유형의 개체일 수 있고 해당 속성이 null이라는 사실에 놀랄 것입니다. 무슨 일이 일어나고 있는 걸까요? 앞서 session.load() 메소드가 엔터티 객체의 프록시 클래스 객체를 반환한다고 언급한 것을 기억하세요. 여기서 반환되는 객체 유형은 User 객체의 프록시 클래스 객체입니다. Hibernate에서 CGLIB는 대상 객체의 프록시 클래스 객체를 동적으로 구성하는 데 사용되며 프록시 클래스 객체에는 대상 객체의 모든 속성과 메서드가 포함되며 모든 속성에는 null이 할당됩니다. 디버거가 표시하는 메모리 스냅샷을 통해 현재의 실제 User 객체가 Proxy 객체의 CGLIB$CALBACK_0.target 속성에 포함되어 있음을 알 수 있습니다. (2)로 코드가 실행되면 user.getName(이 호출됩니다. 이때 ) 메소드는 이때 CGLIB에서 제공하는 콜백 메커니즘을 통해 CGLIB$CALBACK_0.getName() 메소드가 실제로 호출됩니다. 이 메소드를 호출하면 Hibernate는 먼저 CGLIB$CALBACK_0.target 속성이 null인지 확인합니다. null이 아니면 대상 객체의 getName 메소드를 호출합니다. 비어 있으면 데이터베이스 쿼리가 시작되고 다음과 유사한 SQL 문이 생성됩니다. 데이터를 쿼리하고, 대상 개체를 구성하고, 이를 CGLIB $CALBACK_0.target 속성에 할당합니다.

이러한 방식으로 중간 프록시 객체를 통해 Hibernate는 사용자가 실제로 엔터티 객체의 속성을 얻기 위한 작업을 시작할 때만 데이터베이스 쿼리 작업이 실제로 시작됩니다. 따라서 엔티티의 지연 로딩은 중간 프록시 클래스를 통해 완료되므로 session.load() 메소드만이 엔티티의 프록시 클래스 객체를 반환하므로 session.load() 메소드만이 엔티티의 지연 로딩을 사용하게 됩니다. 수업.

B. 컬렉션 유형의 지연 로딩:

Hibernate의 지연 로딩 메커니즘에서 컬렉션 유형의 적용은 성능을 크게 향상시킬 수 있기 때문에 가장 중요합니다. JDK 컬렉션의 독립적 구현을 ​​포함하여 많은 노력을 기울였습니다. 일대다 관계에서 관련 객체를 수용하기 위해 정의한 Set 컬렉션은 java.util.Set 유형이나 해당 하위 유형이 아니라 net입니다. sf.hibernate.collection.Set 유형. 사용자 정의 컬렉션 클래스의 구현을 사용하여 Hibernate는 컬렉션 유형의 지연 로딩을 구현합니다. 컬렉션 유형에 지연 로딩을 사용하려면 엔터티 클래스의 연결 부분을 다음과 같이 구성해야 합니다.

<클래스 이름=”com.neusoft.entity.User” 테이블=”사용자”>

…..


<키 열=”user_id”/>

<일대다 클래스=”com.neusoft.entity. Arrderss"/>







요소의 지연 속성을 설정하여 컬렉션 유형의 지연 로딩 기능을 활성화합니다. 다음 코드를 살펴보겠습니다.

User user=(User)session.load(User.class,”1”)

Collection addset=user.getAddresses() (1)

Iterator it=addset.iterator(); (2)

while(it.hasNext()){

주소 address=(Address)it.next();

System.out.println(address.getAddress())

}

프로그램이 ( 1), 관련 데이터를 로드하기 위한 쿼리가 시작되지 않습니다. (2)에 도달한 경우에만 Hibernate는 캐시에 있는 정규화된 데이터를 기반으로 시작합니다. 조건에 맞는 엔터티 개체를 찾습니다.

여기에서는 데이터 인덱스라는 새로운 개념을 소개합니다. 다음으로 먼저 데이터 인덱스가 무엇인지 살펴보겠습니다. Hibernate에서 컬렉션 유형을 캐시할 때 두 부분으로 캐시됩니다. 먼저 컬렉션에 있는 모든 엔터티의 id 목록이 캐시되고, 그런 다음 이러한 엔터티 개체의 id 목록이 소위 데이터입니다. 색인. 데이터 인덱스를 검색할 때 해당 데이터 인덱스가 없으면 Select SQL이 실행되어 정규화된 데이터를 얻고 엔터티 개체 컬렉션과 데이터 인덱스를 구성한 다음 엔터티 개체 컬렉션을 반환하고 엔터티를 추가합니다. Hibernate의 캐시에 객체와 데이터 인덱스를 넣습니다. 반면, 해당 데이터 인덱스가 발견되면 데이터 인덱스에서 id 목록을 가져온 다음, 해당 id에 따라 해당 엔터티를 캐시에서 검색하고, 발견되지 않으면 캐시에서 반환합니다. 발견되면 선택 SQL 쿼리가 시작됩니다. 여기서는 성능에 영향을 미칠 수 있는 또 다른 문제, 즉 컬렉션 유형의 캐싱 전략을 볼 수 있습니다. 컬렉션 유형을 다음과 같이 구성하면:

<클래스 이름=”com.neusoft.entity.User” 테이블=”사용자”>

…..


<캐시 사용량=”읽기 전용”/>

<키 열=”user_id”/>
<일대다 클래스=”com.neusoft.entity.Arrderss”/>





이 전략을 사용하여 구성하는 경우 여기서는 컬렉션 유형인 Hibernate는 컬렉션의 엔터티 객체가 아닌 데이터 인덱스만 캐시합니다. 위에서 구성한 대로 다음 코드를 실행합니다.

User user=(User)session.load(User.class,”1”)

Collection addset=user.getAddresses();

Iterator it=addset.iterator(); 🎜>System.out.println(address.getAddress())

System.out.println(“ 두 번째 쿼리…”);

User user2 =(User)session.load(User.class,”1”)

Collection it2=user2.getAddresses(); 🎜>while(it2.hasNext()){

주소 주소2=(Address)it2.next()

System.out.println(address2.getAddress())

}

이 코드를 실행하면 다음과 유사한 출력이 표시됩니다.

Select * from user where id='1'; user_id='1'인 주소;

천진

대련

두 번째 쿼리...

id='1'인 주소에서 * 선택;

id='2'인 주소에서 *를 선택합니다.

Tianjin

Dalian

두 번째 쿼리를 실행하면 주소 테이블에 대한 두 가지 쿼리 작업이 실행되는 이유는 무엇입니까? 이는 컬렉션 유형 캐시 전략의 구성에 따라 엔터티가 처음 로드될 때 컬렉션 데이터 인덱스만 캐시되고 컬렉션에 포함된 엔터티 개체는 캐시되지 않기 때문입니다. 따라서 엔터티를 로드할 때. 두 번째로 Hibernate는 해당 엔터티의 데이터 인덱스를 찾았지만 데이터 인덱스에 따르면 캐시에서 해당 엔터티를 찾을 수 없었습니다. 따라서 Hibernate는 발견된 데이터 인덱스를 기반으로 두 개의 SQL 선택 쿼리 작업을 시작했습니다. 이로 인해 성능이 낭비되는 것을 어떻게 방지할 수 있습니까? 또한 컬렉션 유형의 엔터티에 대한 캐시 전략을 지정해야 하므로 다음과 같이 컬렉션 유형을 구성해야 합니다.


<클래스 이름=”com.neusoft.entity.User” 테이블=”사용자”>

…..


<캐시 사용량=”읽기-쓰기”/>

<키 열=”user_id”/>
<일대다 클래스=”com.neusoft.entity.Arrderss”/>





이때 이 구성에 따라 위의 코드를 다시 실행하면 Hibernate도 해당 컬렉션 유형에 캐시됩니다. 다음과 유사한 출력이 표시됩니다.

Select * from user where id='1';

Select * from address where user_id='1';

대련

두번째 질의...

천진

대련

이때 컬렉션 형식에 저장된 엔터티 개체를 캐시에서 직접 가져올 수 있으므로 데이터 인덱스를 기반으로 쿼리하는 SQL 문은 더 이상 없습니다.

C. 속성 지연 로딩:

Hibernate3에는 속성의 지연 로딩이라는 새로운 기능이 도입되었습니다. 이 메커니즘은 고성능 쿼리를 얻기 위한 강력한 도구를 제공합니다. 앞서 빅데이터 객체 읽기에 대해 이야기했을 때 User 객체에 이력서 필드가 있는데, 이 필드는 java.sql.Clob 유형이고 객체를 로드할 때마다 이를 로드해야 합니다. 이 필드는 실제로 필요한지 여부에 관계없이 로드되어야 하며 이 큰 데이터 개체를 읽는 것 자체로 인해 많은 성능 오버헤드가 발생합니다. Hibernate2에서는 앞서 언급한 것처럼 세분화된 성능 분할을 통해 User 클래스를 분해함으로써 이 문제를 해결할 수 있지만(해당 섹션의 논의 참조), Hibernate3에서는 게으른 로딩 메커니즘 속성을 사용할 수 있습니다. 이 필드를 실제로 조작해야 하는 경우에만 이 필드의 데이터를 읽을 수 있는 기능을 얻을 수 있습니다. 이렇게 하려면 엔터티 클래스를 다음과 같이 구성해야 합니다.


<클래스 이름=”com.neusoft.entity.User” 테이블=”사용자”>

……

<속성 이름=”이력서” 유형=” java .sql.Clob” 열=”resume” 게으른=”true”/>





요소의 지연 속성을 true로 설정하여 속성의 지연 로딩을 활성화합니다. Hibernate3 지연 로딩은 엔터티 클래스의 클래스 파일을 강화하기 위해 클래스 인핸서를 사용합니다. 인핸서의 강화를 통해 CGLIB의 콜백 메커니즘 로직이 엔터티 클래스에 추가되는 것을 볼 수 있습니다. CGLIB를 통해 실현되었습니다. CGLIB는 Apache의 오픈 소스 프로젝트입니다. 이 클래스 라이브러리는 Java 클래스의 바이트코드를 조작하고 바이트코드를 기반으로 요구사항을 충족하는 클래스 객체를 동적으로 구성할 수 있습니다. 위 구성을 기반으로 다음 코드를 실행합니다.

String sql=”from User user where user.name='zx' ”

Query query=session.createQuery(sql); ( 1)

List list=query.list();

for(int i=0;i
사용자 사용자 = (사용자)list.get(i);

System.out.println(user.getName())

System.out.println(user.getResume()); 2 )

}

실행이 (1)에 도달하면 다음과 유사한 SQL 문이 생성됩니다.

name=인 사용자에서 id,age,name을 선택합니다. 'zx'; 이때 Hibernate는 User 엔터티의 모든 non-lazy loading 속성에 해당하는 필드 데이터를 검색합니다. 실행이 (2)에 도달하면 다음과 유사한 SQL 문이 생성됩니다. :

id='1'인 사용자의 이력서를 선택하세요.





1. 존재하지 않는 레코드 로드
Employee Employees2 = (Employee) session.load(Employee.class, new Integer(100));

은 net.sf.hibernate.ObjectNotFoundException을 발생시킵니다.

이 Exception을 발생시키지 않으려면 session.get(Class clazz, Serialized id)을 사용해야 합니다.

2. 데이터베이스에 존재하는 레코드를 로드합니다
1) 세션의 캐시에 존재하는 경우 참조를 직접 반환합니다.

세션 세션 = HibernateSessionFactory.currentSession();

트랜잭션 tx = session.beginTransaction();
직원 Employee();
employee1.setAge((byte)10);
employee1.setBirthDay(new Date());
employee1.setEmployeeName("HairRoot");
employee1.setGender('m');
employee1.setMarried(false);
세션. save(employee1);
System.out.println(employee1);

//employ1이 저장되었습니다
직원 Employee2 = (직원) session.load(Employee.class, new Integer(/ / *employee1.getId()*/100));
System.out.println(employee2);
tx.commit();
session.close();

할 수 있습니다. Employee1과 Employee2는 동일한 참조임을 알 수 있습니다. show_sql=true를 켜면 최대 절전 모드가 데이터베이스에 선택 문을 보내지 않는다는 것도 알 수 있습니다.

2) 캐시에 해당 세션이 없으면 즉시 선택이 전송됩니다.

세션 세션 = HibernateSessionFactory.currentSession();

트랜잭션 tx = session.beginTransaction();

직원 직원 = (직원) session.load(Employee.class, new Integer(100));
System.out.println(employee);
tx.commit();
session.close();

백엔드: 최대 절전 모드: Employee0_.id를 id0_로, Employee0_.age를 age0_로 선택 , Employees0_.birthDay는 birthdayDay0_, 직원0_.employeeName은 직원4_0_, 직원0_.gender는 성별0_, 직원0_.결혼으로 결혼함0_ from MWS_TEST_EMPLOYEE 직원0_ 여기서 직원0_.id=?

이때, 쿼리가 시작됩니다. 필드 데이터의 실제 읽기 작업이 재개됩니다.



성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.