백엔드 개발 PHP 튜토리얼 Hibernate的三种延迟加载_PHP教程

Hibernate的三种延迟加载_PHP教程

Jul 13, 2016 pm 05:53 PM
hibernate 관계 동기식 오른쪽 물체 지연 설립하다 일종의 튼튼한 나사 데이터 베이스 ~의 기록

 持久态:对象于数据库记录建立对应关系并保持同步。对象被绑定在持久化上下文当中,今后它的任何状态变化、数据变更均处于工作单元的管理之下,这就是持久态。session.load在hibernate3.2中提供的默认延迟加载方式,我觉得load出来的是一个代理,也可以说是持久态。
     延迟加载机制是为了避免一些无谓的性能开销而提出来的,所谓延迟加载就是当在真正需要数据的时候,才真正执行数据加载操作。在使用延时加载时,用到的对象是一个代理对象,该对象包含被代理对象的所有成员变量和方法,只是在该对象中,该成员变量的值为NULL,在Hibernate中提供了对实体对象的延迟加载以及对集合的延迟加载,另外在Hibernate3中还提供了对属性的延迟加载。下面我们就分别介绍这些种类的延迟加载的细节。
A、实体对象的延迟加载:
     如果想对实体对象使用延迟加载,必须要在实体的映射配置文件中进行相应的配置,如下所示:
     
         
                ……
         

    

     通过将class的lazy属性设置为true,来开启实体的延迟加载特性。如果我们运行下面的代码:
      User user=(User)session.load(User.class,”1”);(1)
     System.out.println(user.getName());(2)
     当运行到(1)处时,Hibernate并没有发起对数据的查询,如果我们此时通过一些调试工具(比如JBuilder2005的Debug工具),或者使用debug断点监视,此时user对象的内存快照,我们会惊奇的发现,此时返回的可能是User$EnhancerByCGLIB$$bede8986类型的对象,而且其属性为null。session.load()方法,会返回实体对象的代理类对象,这里所返回的对象类型就是User对象的代理类对象。在Hibernate中通过使用CGLIB,来实现动态构造一个目标对象的代理类对象,并且在代理类对象中包含目标对象的所有属性和方法,而且所有属性均被赋值为null。通过调试器显示的内存快照,我们可以看出此时真正的User对象,是包含在代理对象的CGLIB$CALBACK_0.target属性中,
     当代码运行到(2)处时,此时调用user.getName()方法,这时通过CGLIB赋予的回调机制,实际上调用CGLIB$CALBACK_0.getName()方法,当调用该方法时,Hibernate会首先检查CGLIB$CALBACK_0.target属性是否为null,如果不为空,则调用目标对象的getName方法,如果为空,则会发起数据库查询,生成类似这样的SQL语句:select * from user where id=’1’;来查询数据,并构造目标对象,并且将它赋值到CGLIB$CALBACK_0.target属性中。这样,通过一个中间代理对象,Hibernate实现了实体的延迟加载,只有当用户真正发起获得实体对象属性的动作时,才真正会发起数据库查询操作。所以实体的延迟加载是用通过中间代理类完成的,所以只有session.load()方法才会利用实体延迟加载,因为只有session.load()方法才会返回实体类的代理类对象。
B、集合类型的延迟加载:
     在Hibernate的延迟加载机制中,针对集合类型的应用,意义是最为重大的,因为这有可能使性能得到大幅度的提高,为此Hibernate进行了大量的努力,其中包括对JDK Collection的独立实现,我们在一对多关联中,定义的用来容纳关联对象的Set集合,并不是java.util.Set类型或其子类型,而net.sf.hibernate.collection.Set类型,通过使用自定义集合类的实现,Hibernate实现了集合类型的延迟加载。为了对集合类型使用延迟加载,我们必须如下配置我们的实体类的关于关联的部分:
     
        
             …
           
              
              
   

    

    

 通过将元素的lazy属性设置为true来开启集合类型的延迟加载特性。我们看下面的代码:
 User user=(User)session.load(User.class,”1”);
 Collection addset=user.getAddresses();       (1)
 Iterator it=addset.iterator();               (2)
 while(it.hasNext()){
      Address address=(Address)it.next();
      System.out.println(address.getAddress());
 }
 当程序执行到(1)处时,这时并不会发起对关联数据的查询来加载关联数据,只有运行到(2)处时,真正的数据读取操作才会开始,这时Hibernate会根据缓存中符合条件的数据索引,来查找符合条件的实体对象。这里我们引入了一个全新的概念——数据索引,下面我们首先将接一下什么是数据索引。在Hibernate中对集合类型进行缓存时,是分两部分进行缓存的,首先缓存集合中所有实体的id列表,然后缓存实体对象,这些实体对象的id列表,就是所谓的数据索引。当查找数据索引时,如果没有找到对应的数据索引,这时就会一条select SQL的执行,获得符合条件的数据,并构造实体对象集合和数据索引,然后返回实体对象的集合,并且将实体对象和数据索引纳入Hibernate的缓存之中。另一方面,如果找到对应的数据索引,则从数据索引中取出id列表,然后根据id在缓存中查找对应的实体,如果找到就从缓存中返回,如果没有找到,在发起select SQL查询。在这里我们看出了另外一个问题,这个问题可能会对性能产生影响,这就是集合类型的缓存策略。如果我们如下配置集合类型:
        
           
   …..
   
    
    
    
   

  

 

 这里我们应用了配置,如果采用这种策略来配置集合类型,Hibernate将只会对数据索引进行缓存,而不会对集合中的实体对象 进行缓存。如上配置我们运行下面的代码:
  User user=(User)session.load(User.class,”1”);
  Collection addset=user.getAddresses();     
  Iterator it=addset.iterator();              
  while(it.hasNext()){
   Address address=(Address)it.next();
   System.out.println(address.getAddress());
  }
  System.out.println(“Second query……”);
  User user2=(User)session.load(User.class,”1”);
  Collection it2=user2.getAddresses();
  while(it2.hasNext()){
  Address address2=(Address)it2.next();
  System.out.println(address2.getAddress());
  }
  运行这段代码,会得到类似下面的输出:
  Select * from user where id=’1’;
  Select * from address where user_id=’1’;
  Tianjin
  Dalian
  Second query……
  Select * from address where id=’1’;
  Select * from address where id=’2’;
  Tianjin
  Dalian
 我们看到,当第二次执行查询时,执行了两条对address表的查询操作,为什么会这样?这是因为当第一次加载实体后,根据集合类型缓存策略的配置,只对集合数据索引进行了缓存,而并没有对集合中的实体对象进行缓存,所以在第二次再次加载实体时,Hibernate找到了对应实体的数据索引,但是根据数据索引,却无法在缓存中找到对应的实体,所以Hibernate根据找到的数据索引发起了两条select SQL的查询操作,这里造成了对性能的浪费,怎样才能避免这种情况呢?我们必须对集合类型中的实体也指定缓存策略,所以我们要如下对集合类型进行配置:
  
      
    …..
    
     
     
     
    

      

  

 此时Hibernate会对集合类型中的实体也进行缓存,如果根据这个配置再次运行上面的代码,将会得到类似如下的输出:
  Select * from user where id=’1’;
  Select * from address where user_id=’1’;
  Tianjin
  Dalian
  Second query……
  Tianjin
  Dalian
 这时将不会再有根据数据索引进行查询的SQL语句,因为此时可以直接从缓存中获得集合类型中存放的实体对象。
C、属性延迟加载:
 在Hibernate3中,引入了一种新的特性——属性的延迟加载,这个机制又为获取高性能查询提供了有力的工具。在前面我们讲大数据对象读取时,在User对象中有一个resume字段,该字段是一个java.sql.Clob类型,包含了用户的简历信息,当我们加载该对象时,我们不得不每一次都要加载这个字段,而不论我们是否真的需要它,而且这种大数据对象的读取本身会带来很大的性能开销。在Hibernate2中,我们只有通过我们前面讲过的面性能的粒度细分,来分解User类,来解决这个问题(请参照那一节的论述),但是在Hibernate3中,我们可以通过属性延迟加载机制,来使我们获得只有当我们真正需要操作这个字段时,才去读取这个字段数据的能力,为此我们必须如下配置我们的实体类:
 
  
   ……
   
    

 

 通过对元素的lazy属性设置true来开启属性的延迟加载,在Hibernate3中为了实现属性的延迟加载,使用了类增强器来对实体类的Class文件进行强化处理,通过增强器的增强,将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   User user=(User)list.get(i);
  System.out.println(user.getName());
  System.out.println(user.getResume());   (2)
 }
 当执行到(1)处时,会生成类似如下的SQL语句:
 Select id,age,name from user where name=’zx’;www.2cto.com
 这时Hibernate会检索User实体中所有非延迟加载属性对应的字段数据,当执行到(2)处时,会生成类似如下的SQL语句:
 Select resume from user where id=’1’;
 这时会发起对resume字段数据真正的读取操作。
作者:oh_Mourinho

www.bkjia.comtruehttp://www.bkjia.com/PHPjc/478064.htmlTechArticle持久态:对象于数据库记录建立对应关系并保持同步。对象被绑定在持久化上下文当中,今后它的任何状态变化、数据变更均处于工作单元...
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

iOS 18에는 손실되거나 손상된 사진을 검색할 수 있는 새로운 '복구된' 앨범 기능이 추가되었습니다. iOS 18에는 손실되거나 손상된 사진을 검색할 수 있는 새로운 '복구된' 앨범 기능이 추가되었습니다. Jul 18, 2024 am 05:48 AM

Apple의 최신 iOS18, iPadOS18 및 macOS Sequoia 시스템 릴리스에는 사진 애플리케이션에 중요한 기능이 추가되었습니다. 이 기능은 사용자가 다양한 이유로 손실되거나 손상된 사진과 비디오를 쉽게 복구할 수 있도록 설계되었습니다. 새로운 기능에는 사진 앱의 도구 섹션에 '복구됨'이라는 앨범이 도입되었습니다. 이 앨범은 사용자가 기기에 사진 라이브러리에 포함되지 않은 사진이나 비디오를 가지고 있을 때 자동으로 나타납니다. "복구된" 앨범의 출현은 데이터베이스 손상으로 인해 손실된 사진과 비디오, 사진 라이브러리에 올바르게 저장되지 않은 카메라 응용 프로그램 또는 사진 라이브러리를 관리하는 타사 응용 프로그램에 대한 솔루션을 제공합니다. 사용자는 몇 가지 간단한 단계만 거치면 됩니다.

Hibernate는 어떻게 다형성 매핑을 구현합니까? Hibernate는 어떻게 다형성 매핑을 구현합니까? Apr 17, 2024 pm 12:09 PM

Hibernate 다형성 매핑은 상속된 클래스를 데이터베이스에 매핑할 수 있으며 다음 매핑 유형을 제공합니다. Join-subclass: 상위 클래스의 모든 열을 포함하여 하위 클래스에 대한 별도의 테이블을 생성합니다. 클래스별 테이블: 하위 클래스별 열만 포함하는 하위 클래스에 대한 별도의 테이블을 만듭니다. Union-subclass: Joined-subclass와 유사하지만 상위 클래스 테이블이 모든 하위 클래스 열을 통합합니다.

MySQL 쿼리 결과 배열을 객체로 변환하는 방법은 무엇입니까? MySQL 쿼리 결과 배열을 객체로 변환하는 방법은 무엇입니까? Apr 29, 2024 pm 01:09 PM

MySQL 쿼리 결과 배열을 객체로 변환하는 방법은 다음과 같습니다. 빈 객체 배열을 만듭니다. 결과 배열을 반복하고 각 행에 대해 새 개체를 만듭니다. foreach 루프를 사용하여 각 행의 키-값 쌍을 새 개체의 해당 속성에 할당합니다. 개체 배열에 새 개체를 추가합니다. 데이터베이스 연결을 닫습니다.

PHP에서 MySQLi를 사용하여 데이터베이스 연결을 설정하는 방법에 대한 자세한 튜토리얼 PHP에서 MySQLi를 사용하여 데이터베이스 연결을 설정하는 방법에 대한 자세한 튜토리얼 Jun 04, 2024 pm 01:42 PM

MySQLi를 사용하여 PHP에서 데이터베이스 연결을 설정하는 방법: MySQLi 확장 포함(require_once) 연결 함수 생성(functionconnect_to_db) 연결 함수 호출($conn=connect_to_db()) 쿼리 실행($result=$conn->query()) 닫기 연결( $conn->close())

PHP에서 데이터베이스 연결 오류를 처리하는 방법 PHP에서 데이터베이스 연결 오류를 처리하는 방법 Jun 05, 2024 pm 02:16 PM

PHP에서 데이터베이스 연결 오류를 처리하려면 다음 단계를 사용할 수 있습니다. mysqli_connect_errno()를 사용하여 오류 코드를 얻습니다. 오류 메시지를 얻으려면 mysqli_connect_error()를 사용하십시오. 이러한 오류 메시지를 캡처하고 기록하면 데이터베이스 연결 문제를 쉽게 식별하고 해결할 수 있어 애플리케이션이 원활하게 실행될 수 있습니다.

PHP에서 배열과 객체의 차이점은 무엇입니까? PHP에서 배열과 객체의 차이점은 무엇입니까? Apr 29, 2024 pm 02:39 PM

PHP에서 배열은 순서가 지정된 시퀀스이며 요소는 인덱스로 액세스됩니다. 객체는 new 키워드를 통해 생성된 속성과 메서드가 있는 엔터티입니다. 배열 액세스는 인덱스를 통해 이루어지며, 객체 액세스는 속성/메서드를 통해 이루어집니다. 배열 값이 전달되고 객체 참조가 전달됩니다.

C++ 함수가 객체를 반환할 때 무엇에 주의해야 합니까? C++ 함수가 객체를 반환할 때 무엇에 주의해야 합니까? Apr 19, 2024 pm 12:15 PM

C++에서는 함수가 객체를 반환할 때 주의해야 할 세 가지 사항이 있습니다. 객체의 수명 주기는 메모리 누수를 방지하기 위해 호출자가 관리합니다. 매달린 포인터를 피하고 메모리를 동적으로 할당하거나 개체 자체를 반환하여 함수가 반환된 후에도 개체가 유효한지 확인하세요. 컴파일러는 성능을 향상시키기 위해 반환된 개체의 복사 생성을 최적화할 수 있지만 개체가 값 의미 체계에 따라 전달되는 경우 복사 생성이 필요하지 않습니다.

Golang에서 데이터베이스 콜백 함수를 사용하는 방법은 무엇입니까? Golang에서 데이터베이스 콜백 함수를 사용하는 방법은 무엇입니까? Jun 03, 2024 pm 02:20 PM

Golang의 데이터베이스 콜백 기능을 사용하면 다음을 달성할 수 있습니다. 지정된 데이터베이스 작업이 완료된 후 사용자 정의 코드를 실행합니다. 추가 코드를 작성하지 않고도 별도의 함수를 통해 사용자 정의 동작을 추가할 수 있습니다. 삽입, 업데이트, 삭제, 쿼리 작업에 콜백 함수를 사용할 수 있습니다. 콜백 함수를 사용하려면 sql.Exec, sql.QueryRow, sql.Query 함수를 사용해야 합니다.

See all articles