FetchType的区别是什么。LAZY和FetchType。Java持久性API中的EAGER ?


当前回答

有一个小小的评论: 如果你使用惰性类型,如果你关闭会话,你以后将不能从数据库中获取数据(参见下面的输出)。

但是对于Eager类型,你在获取Instructor的同时获取数据,所以在session.close()之后,你将能够使用/显示这些课程列表数据。

  @OneToMany(//fetch = FetchType.EAGER, 
        fetch = FetchType.LAZY,  
           mappedBy = "instructor",        
           cascade = {CascadeType.DETACH, CascadeType.MERGE,
                CascadeType.PERSIST, CascadeType.REFRESH})
private List<Course> courseList; 

我建议在调试模式下尝试这两种方法。在这种情况下,我使用惰性类型,你可以看到。

 try {
        //start the transaction
        session.beginTransaction();

        //Get instructor from database
        int instructorId = 7;

        Instructor tempInstructor = session.get(Instructor.class,instructorId);

        System.out.println("Instructor: "+tempInstructor);


        //commit transaction
        session.getTransaction().commit();

       //close session
       session.close();

       //since courselist is lazy loaded... this should fail
       //so in here we are not able to fetch courselist data
       //get courses
        System.out.println("Courses "+tempInstructor.getCourseList() );


        System.out.println("Done!");

    } finally {
        session.close();
        factory.close();
    }
}

输出异常:

Exception in thread "main" org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.exercise.hibernate.entity.Instructor.courseList, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:606)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:218)
at org.hibernate.collection.internal.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:585)
at org.hibernate.collection.internal.AbstractPersistentCollection.read(AbstractPersistentCollection.java:149)
at org.hibernate.collection.internal.PersistentBag.toString(PersistentBag.java:621)
at java.base/java.lang.StringConcatHelper.stringOf(StringConcatHelper.java:453)
at java.base/java.lang.StringConcatHelper.simpleConcat(StringConcatHelper.java:408)
at com.exercise.hibernate.main.EagerLazyLoading.main(EagerLazyLoading.java:56)

其他回答

public enum FetchType extends java.lang.Enum Defines strategies for fetching data from the database. The EAGER strategy is a requirement on the persistence provider runtime that data must be eagerly fetched. The LAZY strategy is a hint to the persistence provider runtime that data should be fetched lazily when it is first accessed. The implementation is permitted to eagerly fetch data for which the LAZY strategy hint has been specified. Example: @Basic(fetch=LAZY) protected String getName() { return name; }

据我所知,这两种类型的取回取决于你的要求。

FetchType。LAZY是按需的(即当我们需要数据时)。

FetchType。EAGER是即时的(即在我们的需求到来之前,我们不必要地获取记录)

默认情况下,对于所有的集合和映射对象,获取规则是FetchType。LAZY,对于其他实例,它遵循FetchType。急切的政策。 简而言之,@OneToMany和@ManyToMany关系并不隐式地获取相关对象(集合和映射),但检索操作通过@OneToOne和@ManyToOne中的字段级联。

(提供:- objectdbcom)

我想在上面说的基础上补充这一点。

假设您正在使用Spring (MVC和数据)与这个简单的架构:

Controller <-> Service <-> Repository

如果你使用FetchType,你想返回一些数据到前端。LAZY,在你将数据返回给控制器方法后,你会得到一个LazyInitializationException,因为会话在服务中关闭了,所以JSON Mapper对象无法获得数据。

根据设计、性能和开发人员的不同,有两种常见的方法来解决这个问题:

最简单的方法是使用FetchType。EAGER或任何其他反模式解决方案,使会话仍然活跃在控制器方法,但这些方法将影响性能。 最佳实践是使用FetchType。LAZY使用映射器(如MapStruct)将数据从Entity传输到另一个数据对象DTO,然后将其发送回控制器,因此会话关闭时没有异常。

有一个简单的例子:

@RestController
@RequestMapping("/api")
public class UserResource {

    @GetMapping("/users")
    public Page<UserDTO> getAllUsers(Pageable pageable) {
        return userService.getAllUsers(pageable);
    }
}

@Service
@Transactional
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Transactional(readOnly = true)
    public Page<UserDTO> getAllUsers(Pageable pageable) {
        return userRepository.findAll(pageable).map(UserDTO::new);
    }
}

@Repository
public interface UserRepository extends JpaRepository<User, String> {

    Page<User> findAll(Pageable pageable);
}

public class UserDTO {

    private Long id;

    private String firstName;

    private String lastName;

    private String email;
    
    private Set<String> addresses;

    public UserDTO() {
        // Empty constructor needed for Jackson.
    }

    public UserDTO(User user) {
        this.id = user.getId();
        this.firstName = user.getFirstName();
        this.lastName = user.getLastName();
        this.email = user.getEmail();
        this.addresses = user.getAddresses().stream()
            .map(Address::getAddress)
            .collect(Collectors.toSet());
    }

    // Getters, setters, equals, and hashCode
}

@Entity
@Table(name = "user")
public class User implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String firstName;

    @Column
    private String lastName;

    @Column(unique = true)
    private String email;
    
    @OneToMany(mappedBy = "address", fetch = FetchType.LAZY)
    private Set<Address> addresses = new HashSet<>();

    // Getters, setters, equals, and hashCode
}

@Entity
@Table(name = "address")
public class Address implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column
    private String address;

    @ManyToOne
    @JsonIgnoreProperties(value = "addresses", allowSetters = true)
    private User user;

    // Getters, setters, equals, and hashCode
}

I may consider performance and memory utilization. One big difference is that EAGER fetch strategy allows to use fetched data object without session. Why? All data is fetched when eager marked data in the object when session is connected. However, in case of lazy loading strategy, lazy loading marked object does not retrieve data if session is disconnected (after session.close() statement). All that can be made by hibernate proxy. Eager strategy lets data to be still available after closing session.