JPA fetchType.Lazy 不工作

Posted

技术标签:

【中文标题】JPA fetchType.Lazy 不工作【英文标题】:JPA fetchType.Lazy is not working 【发布时间】:2013-09-09 08:00:56 【问题描述】:

我正在尝试fetchType.Lazy 的示例,但是在调试代码时,fetchType.Lazy 似乎不起作用。

实体 bean:地址

在区字段上添加了带有属性 fetch=fetchType.Lazy 的注释 @Basic。

我的实体 bean 由以下代码定义:

    package model;

    import java.io.Serializable;
    import javax.persistence.*;
    import java.util.List;


    /**
     * The persistent class for the address database table.
     */
    @Entity
    @Table(name="address", schema="home")
    public class Address implements Serializable 
        private static final long serialVersionUID = 1L;

        @TableGenerator(name = "addr_gen", table = "table_generator", pkColumnName = "gen_name", valueColumnName = "gen_val", allocationSize=1)
        @Id
        @GeneratedValue(strategy=GenerationType.TABLE, generator="addr_gen")
        private String addressId;

        private String city;

        @Basic(fetch=FetchType.LAZY)
        @Column(name="district")
        private String district;

        private String houseNumber;

        private String pincode;

        private String state;

        private String street;

        //bi-directional many-to-one association to Employee
        @OneToMany(mappedBy="address")
        private List<Employee> employees;

        public Address() 
        


        public String getAddressId() 
            return this.addressId;
        

        public void setAddressId(String addressId) 
            this.addressId = addressId;
        

        public String getCity() 
            return this.city;
        

        public void setCity(String city) 
            this.city = city;
        

        public String getDistrict() 
            return this.district;
        

        public void setDistrict(String district) 
            this.district = district;
        

        public String getHouseNumber() 
            return this.houseNumber;
        

        public void setHouseNumber(String houseNumber) 
            this.houseNumber = houseNumber;
        

        public String getPincode() 
            return this.pincode;
        

        public void setPincode(String pincode) 
            this.pincode = pincode;
        

        public String getState() 
            return this.state;
        

        public void setState(String state) 
            this.state = state;
        

        public String getStreet() 
            return this.street;
        

        public void setStreet(String street) 
            this.street = street;
        

        public List<Employee> getEmployees() 
            return this.employees;
        

        public void setEmployees(List<Employee> employees) 
            this.employees = employees;
        


        public Employee addEmployees(Employee employees) 
            getEmployees().add(employees);
            employees.setAddress(this);

            return employees;
        

        public Employee removeEmployees(Employee employees) 
            getEmployees().remove(employees);
            employees.setAddress(null);

            return employees;
        

        /*@Override
        public String toString() 
            return "Address [addressId=" + addressId + ", city=" + city
                    + ", district=" + district + ", houseNumber=" + houseNumber
                    + ", pincode=" + pincode + ", state=" + state + ", street="
                    + street + ", employees=" + employees + "]";
        */
    

使用上述实体bean的方法:

public Address findAddress(EntityManagerFactory emf, UserTransaction tx) 
    EntityManager em = emf.createEntityManager();
    Address addr = null;
    try 
        tx.begin();
        addr = em.find(Address.class, new String("154"));
        tx.commit();
     catch (Exception e) 
        e.printStackTrace();
    

    return addr;

所以在find 方法调用之后,当我检查地址对象时,它已经填充了地区字段。

请让我知道我是否缺少某些配置或代码本身是否存在问题。

【问题讨论】:

作为旁注,但您何时(如果有的话)关闭 EntityManager? 对不起我的错误,我应该在所有操作完成后关闭 entityManager。 【参考方案1】:

问题在于,当在@Basic 注释中使用时,应用程序服务器可以/可能自行决定何时获取数据更好。如记录的here

EAGER 策略是对持久性提供程序运行时的要求,即必须急切地获取值。 LAZY 策略是对持久性提供程序运行时的提示

@OneToMany-like annotations 根据documentation 有同样的问题,但在这种情况下,JPA 提供者更有可能考虑 FetchType 提示。

另一方面,您可以尝试使用大数据字段,例如

@Lob
@Basic(fetch=FetchType.LAZY)
private byte[] document;

查看是否有变化(尽管同样,您的应用程序服务器可以决定始终获取该字段)。

为了检查是否加载了集合字段,我会检查数据库查询日志或执行以下操作:

@PersistenceContext private EntityManager em;
.....
Person person = em.find(Person.class, 1L);//Person entity has a OneToMany relationship to entity Address
em.detach(person);
person.getAddresses().size();//if the Address are now not fetched, it the call should  throw an error

【讨论】:

感谢 Andrei 的回复,我会检查并更新。除此之外,我还尝试了 @ManytoOne 关系,但 fetchType.Lazy 没有用。 我的意思是@OneToMany。在虚构的 Person 实体中试试这个:@OneToMany(fetch=FetchType.LAZY, cascade=CascadeType.ALL) private Setaddresses;并检查数据库日志,当您执行 EntityManager.find(Person.class, 1) 时执行了哪些查询。您如何检查该字段是否已填充? (用 person.getAddressed() 检查它没有意义) 我发布的有问题的相同代码现在工作正常...... :-) 我正在使用调试器检查是否填充了字段。调用 find 方法后,我正在检查对象,并在调用 getter 后检查对象。 @ShashiShankar 请提及您为使代码开始工作所做的工作【参考方案2】:

确保您已启用编织。

http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving

【讨论】:

我使用 glassfish 3.1 作为我的 JPA 提供程序,所以我应该进行编织配置吗? 这个答案是 EclipseLink 特定的,OP 从来没有说过他正在使用 eclipselink。 (现在 FWIW 已弃用)【参考方案3】:

要在JPA中初始化laze,需要调用jar库并启动它,如果是maven或者手动por example,如果需要laze,在maven中使用jar jar de.empulse.eclipselink 更多信息http://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Advanced_JPA_Development/Performance/Weaving/Static_Weaving#Use_the_Maven_plugin

如果你不使用maven,你可以手动启用jar

【讨论】:

以上是关于JPA fetchType.Lazy 不工作的主要内容,如果未能解决你的问题,请参考以下文章

JPA。 FetchType.Lazy 引起了奇怪的行为@ManyToOne

FetchType.Lazy 在 Spring Boot 中无法在 JPA 中工作

Spring Boot 2. Jackson json 序列化或 Spring Data JPA FetchType.Lazy

使用 FetchType.LAZY 防止 JPA/Hibernate 中的延迟加载(尤其是在使用 @Transactional 时)?

JPA 懒加载实践 fetch = FetchType.LAZY

外键 jpa/hibernate 注释不能按预期工作