Hibernate:findById 与 getbyId

mil*_*bos 19 spring hibernate jpa repository

有这样的课程:

用户.java

@Entity
@Setter
@Getter
@NoArgsConstructor
public class User {
    @Id
    private int id;
    private String username;
    @OneToOne(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private Address address;

    public User(String username) {
        this.username = username;
    }
}
Run Code Online (Sandbox Code Playgroud)

地址.java

@Entity
@Data
public class Address {
    @Id
    private int id;
    private String country;
    @OneToOne
    private User user;
}
Run Code Online (Sandbox Code Playgroud)

用户存储库.java

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {
}
Run Code Online (Sandbox Code Playgroud)

演示应用程序.java

@Bean
    public CommandLineRunner loadData(UserRepository userRepo){
        return new CommandLineRunner() {
            @Override
            public void run(String... args) throws Exception {
                User u = new User("motherfucker");
                Address a = new Address();
                a.setCountry("CZ");
                u.setAddress(a);
                a.setUser(u);
                userRepo.save(u);

                //User newUser = userRepo.getById(0);
                User newUser = userRepo.findById(0).orElse(null);
                System.out.println(newUser.getUsername());
            }
        };
    }
Run Code Online (Sandbox Code Playgroud)

现在工作没有问题(在from which extendsfindById(int: id)中定义)。然而,(在 中定义)甚至给出了映射中指定的属性。在文档中它说CrudRepositoryJpaRepositorygetById(int :id)JpaRepositoryLazyInitializationExceptionfetch = Fetch.EAGER

返回对具有给定标识符的实体的引用。根据 JPA 持久性提供程序的实现方式,这很可能始终返回一个实例并在第一次访问时抛出 EntityNotFoundException。其中一些会立即拒绝无效标识符。

  1. 我没得到EntityNotFoundException但是LazyInitializationException
  2. 为什么有一个方法在其文档中声明它无故抛出异常?->总是返回一个实例并抛出EntityNotFoundException

从这个描述来看,对我来说,如果这个方法总是抛出异常,那么它就没用。为什么会有这个方法存在?

在休眠中获取数据的正确方法(方法)是什么?

小智 15

通常我们可以使用 findById 或 getById 。使用其中任何一个都没有问题。

但如果我们想了解更具体的差异,这些差异如下:

- getById:仅当我们确定从数据库中获取我们请求的实体时才使用此方法。如果我们没有得到任何实体,则会出现异常。这就像一个孩子想要什么就得到什么,但如果没有得到他想要的东西,他就会开始尖叫。

- findById:如果我们不确定数据库中是否存在所请求的实体,则使用此方法。因此,即使该实体不存在于数据库中,它也会返回 null 并且不会引发任何异常。


Joã*_*ias 8

  1. 你得到的LazyInitializationException正是因为你设置了fetch = Fetch.EAGERgetById()返回一个延迟获取的实体,从而返回异常。
  2. 这里只是猜测,但也许是因为 的懒惰行为getById()。但说实话我也不明白。

强调另一个细节也很重要:方法内部findById()使用方法并使用方法。结果,返回实际对象并返回实体的引用。EntityManager find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String,Object> properties))getById()EntityManager getReference(Class<T> entityClass, Object primaryKey)findById()getById

参考文档:


Olg*_*aya 7

getById -> 返回实际实体的引用代理。其中仅设置了 id(因为您已经通过了它)。该对象的 getter 和 setter 可以在同一个 @Transaction 中调用。但是,一旦退出事务,代理将返回 LazyInitializationException。

getById 实现

如果你查看 getReference java 文档。我相信这一切都清楚了。因此,如果您调用 getById,hibernate不会访问数据库

获取一个实例,其状态可以被延迟获取。如果数据库中不存在请求的实例,则首次访问实例状态时会抛出EntityNotFoundException。(当调用 getReference 时,允许持久性提供程序运行时抛出 EntityNotFoundException。)应用程序不应期望实例状态在分离时可用,除非应用程序在实体管理器打开时访问了实例状态。

另一方面,findById直接命中DB并执行select查询。