28

I use JPA (Hibernate) with Spring. When I want to lazy load a String property, i use this syntax:

@Lob
@Basic(fetch = FetchType.LAZY)
public String getHtmlSummary() {
    return htmlSummary;
}

But when I look at the sql that hibernate creates, it seems this property is not lazy loaded? I also use this class org.hibernate.tool.instrument.javassist.InstrumentTask in ANT script to instrument this property but it seems it does not work.

BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
Khosro
  • 1
  • 1
  • 2
  • 4

8 Answers8

13

First of all, you should know that the JPA specs clearly specifies that LAZY is only a hint to JPA providers, so it's not a mandatory requirement.

For basic type lazy fetching to work, you need to enable bytecode enhancement and explicitly set the enableLazyInitialization configuration property to 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>
Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
  • 3
    i included this plugin but still not works. (In Select of Entity, the column of file is projected too) – Henrique Fernandes Cipriano Mar 19 '18 at 15:53
  • "For basic type lazy fetching to work ...". This means enabling it is not necessary for ManyToOne fields? If so, what happens if i set it to true for these kind of fields? – Arash Nov 03 '19 at 06:20
  • Thanks Vlad. I set **lazy fetching** for **ManyToOne unidirectional** but didn't set **enableLazyInitialization** to true and checked hibernate log and it didn't fetch the association along with the parent entity it means to me, everything is fine. Should i set **enableLazyInitialization** to true if i don't use any lazy fetching for basic type? – Arash Nov 03 '19 at 08:07
  • 2
    As stated in this StackOverflow answer, **enableLazyInitialization** is only needed for **basic type lazy fetching to work**. Associations can be fetched lazily if they are marked with `FetchType.LAZY` without needing any extra setting. – Vlad Mihalcea Nov 03 '19 at 09:16
7

Lazy Lob loading would require bytecode instrumentation to work properly, so it is not available by default in any JPA implementation I'm aware of.

Your best bet is to put the Lob into a separate entity, like HtmlSummary, and use a lazily loaded one-to-one association.

Henning
  • 16,063
  • 3
  • 51
  • 65
  • Would you please tell me how to instrument?I use Hibernate implementation of JPA.I also do instruction describe here but ,it does not works :http://docs.jboss.org/hibernate/stable/core/reference/en/html_single/#performance-fetching-lazyproperties – Khosro Jan 21 '10 at 21:29
  • @Khosro: What does the Ant log output say? "Does not work" is not quite enough information to diagnose your problem, I'm afraid. – Henning Jan 21 '10 at 21:38
  • Well,my Ant task works well ,and the output is [instrument] accepting transformation of field access [N ews.textBody] but after running apps i got this exception org.hibernate.MappingException: Could not determine type for: org.hibernate.repackage.cglib.transform.impl.InterceptFieldCallback, at table: News, for columns: [org.hibernate.mapping.Column(interceptFieldCallback)] in this case i use org.hibernate.tool.instrument.cglib.InstrumentTask for instrumenting. In another case when i use org.hibernate.tool.instrument.javassist.InstrumentTask ,apps deploys but lazy loading does not works – Khosro Jan 21 '10 at 22:02
  • "does not works " means that ,when i fetch News from database ,it also fetches textBody,but according to lazy loading it must not fetched. – Khosro Jan 21 '10 at 22:03
  • @Khosro:Is org.hibernate.repackage.cglib.transform.impl.InterceptFieldCallback on your classpath at runtime? – Henning Jan 22 '10 at 05:56
  • Henning ,Yes,this class is in hibernate3.jar that i place it in classpath.Also i use JPA(Hibernate implementation) – Khosro Jan 22 '10 at 15:51
  • And i think if this class in not in my classpath i must get this exception " java.lang.NoClassDefFoundError" not this exception Could not determine type for: org.hibernate.repackage.cglib.transform.impl.InterceptFieldCallback, at table: News, for columns: [org.hibernate.mapping.Column(interceptFieldCallback) – Khosro Jan 22 '10 at 17:53
  • "so it is not available by default in any JPA implementation" There are clearly JPA implementations that use bytecode enhancement by default ... DataNucleus JPA for one, so yes it is available by default in some – Neil Stockton Mar 06 '15 at 11:56
3

Use FieldHandled with @Basic(fetch=FetchType.LAZY) works:

public class myFile implements Serializable, FieldHandled
{

    private FieldHandler      fieldHandler;

    @Lob
    @Basic(fetch = FetchType.LAZY)
    @Column(name = "CONTENT")
    protected byte[]          content;
rationalboss
  • 5,330
  • 3
  • 30
  • 50
William
  • 1
  • 1
3
@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;
    }
}

I use Hibernate4 h2database.I am sure lazy loading can work fine by my code.

Hibernate: 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=?

Hibernate: select user_.img as img3_0_ from User user_ where user_.uid=?

if use repository.save(User) to add a new User will be ok, but update a User will throw a exception

java.lang.ClassCastException: org.hibernate.bytecode.instrumentation.spi.LazyPropertyInitializer$1 cannot be cast to java.sql.Blob

I suggest use repository.delete(userid) before repository.save in one transactional, then it will work fine.

lionyu
  • 593
  • 3
  • 5
  • 14
2

from the specification of JPA they say that even if you use annotate a property to be fetched lazily, this is not guaranteed to be applied, so the properties may or may not be loaded lazily (depends on the implementer of JPA), however if you specify that you should fetch them Eagerly then the JPA implementer must load them eagerly.

Bottom line: @Basic(fetch = FetchType.LAZY) may or may not work, depends on the JPA implementer.

BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
Omar Al Kababji
  • 1,768
  • 4
  • 16
  • 31
  • I use Hibernate ,and i describe the problem here http://stackoverflow.com/questions/2112508/basicfetch-fetchtype-lazy-does-not-work/2112846#2112846 in Henning's answer – Khosro Jan 21 '10 at 22:10
1

I had my column annotated with @Lob and its type was byte[] but it was always eager loaded.

I tried to:

  • annotate it with @Basic(fetch = FetchType.LAZY)
  • set hibernate.bytecode.use_reflection_optimizer=false

But none of these solutions worked.

I ended up with using Blob instead of byte[]

@Column(name = "BlobField", nullable = false)
@Lob
@Basic(fetch = FetchType.LAZY)
private Blob blobField;

This one gets lazily loaded and if you need to retrieve its value access this field:

String value = IOUtils.toByteArray(entity.getBlobField().getBinaryStream());
BuZZ-dEE
  • 6,075
  • 12
  • 66
  • 96
michal.jakubeczy
  • 8,221
  • 1
  • 59
  • 63
0

I think that it would be similar to EclipseLink, there you need to have enabled weaving otherwise, the fetch setting takes no effect. The weaving requires bytecode access. This could help: https://stackoverflow.com/a/18423704/7159396

-3

Lazy fetching only applies to references to other entities or collections of entities. It does not apply to values like String or int.

Mark Thornton
  • 1,885
  • 1
  • 12
  • 4
  • Not true, LOBs can be lazy-loaded. See Section 2.2.2.1 of the hibernate-annotations documentation: http://docs.jboss.org/hibernate/stable/annotations/reference/en/html/entity.html#d0e342 -- specifically the 'detailedComment' property on that example, and the note below it. – Cowan Jan 22 '10 at 02:30