En este capítulo, utilizaremos una relación de uno a muchos entre EntidadClase y Estudiante;
Estudiante.java:
package com.cy.modelo;
public class Estudiante {
private int identificador;
private String nombre;
private EntidadClase clase;
public int getIdentificador() {
return identificador;
}
public void setIdentificador(int identificador) {
this.identificador = identificador;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public EntidadClase getClase() {
return clase;
}
public void setClase(EntidadClase clase) {
this.clase = clase;
}
}
EntidadClase.java:
package com.cy.modelo;
import java.util.HashSet;
import java.util.Set;
public class EntidadClase {
private int identificador;
private String nombre;
private Set<Estudiante> estudiantes = new HashSet<Estudiante>();
public int getIdentificador() {
return identificador;
}
public void setIdentificador(int identificador) {
this.identificador = identificador;
}
public String getNombre() {
return nombre;
}
public void setNombre(String nombre) {
this.nombre = nombre;
}
public Set<Estudiante> getEstudiantes() {
return estudiantes;
}
public void setEstudiantes(Set<Estudiante> estudiantes) {
this.estudiantes = estudiantes;
}
}
Estudiante.hbm.xml:
<hibernate-mapping package="com.cy.modelo">
<class name="Estudiante" table="t_estudiante">
<id name="identificador" column="stuId">
<generator class="native"></generator>
</id>
<property name="nombre" column="stuNombre"></property>
<many-to-one name="clase" column="classId" class="com.cy.modelo.EntidadClase" cascade="save-update" lazy="proxy"></many-to-one>
</class>
</hibernate-mapping>
EntidadClase.hbm.xml:
<hibernate-mapping package="com.cy.modelo">
<class name="EntidadClase" table="t_clase">
<id name="identificador" column="classId">
<generator class="native"></generator>
</id>
<property name="nombre" column="className"></property>
<set name="estudiantes" cascade="save-update" inverse="true" lazy="false" batch-size="3" fetch="join">
<key column="classId"></key>
<one-to-many class="com.cy.modelo.Estudiante" />
</set>
</class>
</hibernate-mapping>
Sección 1: Atributo de estrategia de recuperación Lazy
Lazy:true: Recuperación diferida por defecto: se carga cuando se utiliza
@Test
public void testLazy1(){
//En el archivo clase.hbm, en el lado set (uno a muchos), se configura lazy=true,
//por lo que al cargar la clase, los estudiantes no se cargan por defecto.
EntidadClase clase = (EntidadClase) session.get(EntidadClase.class, 1);
//¿Cuándo se consultan los datos de los estudiantes? - cuando se necesitan
//Se recupera solo cuando se utiliza, esto es recuperación diferida
Set<Estudiante> estudiantes = clase.getEstudiantes();
System.out.println(estudiantes.size());
// Iterator it = estudiantes.iterator();
}
lazy:false: Al consultar la clase, si se va a utilizar seguro la información del estudiante, se puede recuperar inmediatamente; también se puede configurar lazy=false lazy:extra: También es diferido, pero mejorado;Por ejemplo, si se configura lazy=true y se desea saber la cantidad de estudiantes consultados:EntidadClase c = (EntidadClase) session.get(EntidadClase.class, 1);Set<Estudiante> estudiantes = c.getEstudiantes();System.out.println(estudiantes.size());El SQL emitido consulta todos los estudiantes y luego se obtienen 3 registros;Pero en realidad solo se necesita select count(*) from estudiante, esto es optimización de SQL. Configurando lazy=extra se puede lograr;Sin embargo, en el desarrollo real no se utiliza mucho, porque rara vez se consulta solo el tamaño; lazy:proxy:Al obtener información del Estudiante, la EntidadClase interna es una clase proxy, que no contiene datos; pero cuando se utiliza el contenido de EntidadClase, se consutla la base de datos a través de la clase proxy.``` @Test public void testLazy2(){ //En el lado many-to-one, lazy es proxy por defecto. La EntidadClase en el estudiante obtenido es una clase proxy. Sin datos reales. Estudiante estudiante = (Estudiante) session.get(Estudiante.class, 1);
//Cuando se utiliza el nombre de la clase, la clase proxy emite una consulta SQL para obtener los datos.
estudiante.getClase().getNombre();
}
lazy:no-proxy:No hay clase proxy, al obtener estudiante, la clase es un valor nulo, hasta que se utiliza el contenido de la clase, se consulta. Rara vez se utiliza.......Sección 2: Atributo de estrategia de recuperación batch-size
1, Recuperación diferida por lotes;
La configuración correspondiente en clase.hbm: lazy="true" batch-size="3"
/** * Recuperación diferida por lotes, lazy=true */ @Test public void testBatch1(){ List<EntidadClase> listaClases = session.createQuery("from EntidadClase").list(); Iterator<EntidadClase> it = listaClases.iterator(); EntidadClase c1 = it.next(); EntidadClase c2 = it.next(); EntidadClase c3 = it.next(); c1.getEstudiantes().iterator(); c2.getEstudiantes().iterator(); c3.getEstudiantes().iterator();
//Primero se obtienen todas las clases, porque en el lado set de estudiantes se configuró lazy=false
//Cuando c1, c2, c3 necesitan estudiantes, es cuando se busca. Cada uno emite una sentencia SQL.
//Si listaClases es muy muy grande, recorrer cada clase y luego obtener los estudiantes de cada clase,
//cualquier emite una sentencia SQL, la eficiencia sería muy baja.
//Por eso se introduce batch-size, recuperación por lotes. El valor de batch-size es el tamaño del lote
//En el archivo clase.hbm, en el set de estudiantes, configurando batch-size=3, la sentencia SQL emitida sería así:
/**
* SELECT
t_estudiante.classId ,
t_estudiante.stuId ,
t_estudiante.stuNombre
FROM t_estudiante
WHERE t_estudiante.classId IN (1, 2, 3)
*/
}
Mientras que sin configurar recuperación por lotes batch-size, la sentencia SQL es así, una por una:
Después de configurar recuperación por lotes, batch-size=3, al consultar información de estudiantes, se consultan 3 de una vez;
2, Recuperación inmediata por lotes;
@Test public void testBatch2(){ List<EntidadClase> listaClases = session.createQuery("from EntidadClase").list(); //Aquí en el archivo clase.hbm.xml, en el set de estudiantes se configura lazy=false, batch-size=3, //lo que significa recuperación inmediata por lotes. //La santencia SQL por lotes es la misma que arriba.
}
Sección 3: Atributo de estrategia de recuperación Fetch
Fetch también se configura en el lado de la clase; fetch:subselect, cuando los datos son muy grandes, usar subconsulta puede optimizar el rendimiento. ```
@Test
public void testFetch1(){
List<EntidadClase> listaClases = session.createQuery("from EntidadClase").list();
Iterator<EntidadClase> it = listaClases.iterator();
EntidadClase c1 = it.next();
EntidadClase c2 = it.next();
EntidadClase c3 = it.next();
c1.getEstudiantes().iterator();
c2.getEstudiantes().iterator();
c3.getEstudiantes().iterator();
/**
* En el archivo clase.hbm, configuración del set de estudiantes: fetch="select", es el valor por defecto, la sentencia SQL emitida:
* SELECT
t_estudiante.classId ,
t_estudiante.stuId ,
t_estudiante.stuNombre
FROM t_estudiante
WHERE t_estudiante.classId IN (1, 2, 3)
Ahora cambiamos a fetch=subselect: la sentencia SQL se convierte en:
SELECT
t_estudiante.classId ,
t_estudiante.stuId ,
t_estudiante.stuNombre
FROM t_estudiante
WHERE t_estudiante.classId IN
(SELECT classId FROM t_clase )
*
*/
}
fetch:join:
@Test
public void testFetch2(){
EntidadClase c = (EntidadClase) session.get(EntidadClase.class, 1);
/**
* Aquí en el archivo clase.hbm se configura:<set name="estudiantes" lazy="false" fetch="join">
* Al consultar la clase, también se recuperan los estudiantes que pertenecen a esta clase, aquí fetch=join, SQL con left outer join:
* La sentencia SQL emitida:
* SELECT
t_clase.classId,
t_clase.className,
t_estudiante.stuId,
t_estudiante.stuNombre,
t_estudiante.classId
FROM t_clase
LEFT OUTER JOIN t_estudiante ON t_clase.classId = t_estudiante.classId
WHERE t_clase.classId = 1
* Se ve que solo se emite una sentencia SQL, las tablas t_clase y t_estudiante se关联,
* la información de la clase y del estudiante se obtienen juntos;
*
* Mientras que si fetch es select, primero se obtiene la información de la clase; luego se obtiene la información del estudiante
*/
}