java - lazyinitializationexception - lazy hibernate example
@Basic(fetch=FetchType.LAZY) no funciona? (7)
Yo uso JPA (Hibernate) con Spring. Cuando quiero cargar de forma perezosa una propiedad Stirng, uso esta sintaxis:
@Lob
@Basic(fetch = FetchType.LAZY)
public String getHtmlSummary() {
return htmlSummary;
}
¿Pero cuando miro el sql que crea hibernate, parece que esta propiedad no se carga de forma perezosa? También uso esta clase org.hibernate.tool.instrument.javassist.InstrumentTask en el script ANT para instrumentar esta propiedad, pero parece que no funciona.
Por favor, ayúdame.
Khosro.
Creo que sería similar a EclipseLink, ya que es necesario habilitar el tejido, de lo contrario, la configuración de búsqueda no tendrá efecto. El tejido requiere acceso bytecode. Esto podría ayudar: https://.com/a/18423704/7159396
En primer lugar, debe saber que las especificaciones de JPA especifican claramente que LAZY es solo una sugerencia para los proveedores de JPA, por lo que no es un requisito obligatorio.
Para que el tipo básico de recuperación perezosa funcione, debe habilitar la mejora del enableLazyInitialization
y establecer explícitamente la propiedad de configuración enableLazyInitialization
en true
:
<plugin>
<groupId>org.hibernate.orm.tooling</groupId>
<artifactId>hibernate-enhance-maven-plugin</artifactId>
<version>${hibernate.version}</version>
<executions>
<execution>
<configuration>
<enableLazyInitialization>true</enableLazyInitialization>
</configuration>
<goals>
<goal>enhance</goal>
</goals>
</execution>
</executions>
</plugin>
La carga de Lazy Lob
requeriría que la instrumentación de código de bytes funcione correctamente, por lo que no estoy disponible de forma predeterminada en ninguna implementación de JPA que conozca.
Su mejor apuesta es colocar el Lob en una entidad separada, como HtmlSummary
, y usar una asociación de uno a uno cargada perezosamente.
La recuperación diferida solo se aplica a las referencias a otras entidades o colecciones de entidades. No se aplica a valores como String o int.
Use FieldHandled con @Basic(fetch=FetchType.LAZY)
funciona:
public class myFile implements Serializable, FieldHandled
{
private FieldHandler fieldHandler;
@Lob
@Basic(fetch = FetchType.LAZY)
@Column(name = "CONTENT")
protected byte[] content;
a partir de la especificación de JPA, dicen que incluso si utiliza anotar una propiedad para que se recupere perezosamente, no se garantiza que esto se aplique, por lo que las propiedades pueden o no cargarse perezosamente (depende del implementador de JPA), sin embargo, si Especifique que debe buscarlos de forma impaciente, entonces el implementador de JPA debe cargarlos con entusiasmo.
Línea inferior: @Basic (fetch = FetchType.LAZY) puede o no funcionar, depende del implementador de JPA.
@Entity
public class User implements FieldHandled {
@Id
private String uid;
private String uname;
private int age;
@Lob
@Basic(fetch = FetchType.LAZY)
private byte[] img;
private FieldHandler fieldHandler;
public User() {
}
// getter() and setter() of uid, uname, age
public byte[] getImg() {
// if User user = new User() then fieldHandler is null
// if User user = entityManager.find(User.class, "001") then fieldHandler is not null
if(img != null) {
return img;
}
if (fieldHandler != null) {
return (byte[]) fieldHandler.readObject(this, "img", img);
} else {
return null;
}
}
public void setImg(byte[] img) {
this.img = img;
}
public void setFieldHandler(FieldHandler fieldHandler) {
this.fieldHandler = fieldHandler;
}
public FieldHandler getFieldHandler() {
return fieldHandler;
}
}
Utilizo Hibernate4 h2database. Estoy seguro de que la carga perezosa puede funcionar bien con mi código.
Hibernación: select user0_.uid as uid1_0_0_, user0_.age as age2_0_0_, user0_.uname as uname4_0_0_ from User user0_ where user0_.uid=?
Hibernación: select user_.img as img3_0_ from User user_ where user_.uid=?
si se usa repository.save(User)
para agregar un nuevo Usuario estará bien, pero actualizar un Usuario lanzará una excepción
java.lang.ClassCastException: org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer$1 cannot be cast to java.sql.Blob
Sugiero usar repository.delete(userid)
antes de repository.save
en una transacción, entonces funcionará bien.