Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: findById vs getbyId

having this classes:

User.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;
    }
}

Address.java:

@Entity
@Data
public class Address {
    @Id
    private int id;
    private String country;
    @OneToOne
    private User user;
}

UserRepository.java:

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

DemoApplcation.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());
            }
        };
    }

Now the findById(int: id) works without problem (defined in CrudRepository from which extends JpaRepository). However the getById(int :id) (defined in JpaRepository) gives LazyInitializationException even with fetch = Fetch.EAGER attribute specified in mapping. In documentation it says

Returns a reference to the entity with the given identifier. Depending on how the JPA persistence provider is implemented this is very likely to always return an instance and throw an EntityNotFoundException on first access. Some of them will reject invalid identifiers immediately.

  1. I didn't get EntityNotFoundException but LazyInitializationException
  2. Why is there a method which declares in its documentation that it throws exception without any reason? -> always return an instance and throw an EntityNotFoundException

from this description it seems for me this method be useless if it always throws exception. Why does this method exists?

What is the right way (method) for fetching data in hibernate?

like image 460
milanHrabos Avatar asked Oct 14 '22 20:10

milanHrabos


People also ask

What is difference between getOne and findById?

Both findById() and getOne() methods are used to retrieve an object from underlying datastore. But the underlying mechanism for retrieving records is different for both these methods, infact getOne() is lazy operation which does not even hit the database.

What is findById in JPA?

The findById() method is used to retrieves an entity by its id and it is available in CrudRepository interface. The CrudRepository extends Repository interface. In Spring Data JPA Repository is top-level interface in the hierarchy. Here we are going to see the findById() method of CrudRepository.

What is difference between JpaRepository and PagingAndSortingRepository?

PagingAndSortingRepository provides methods to do pagination and sort records. JpaRepository provides JPA related methods such as flushing the persistence context and delete records in a batch.

Which is better Hibernate or Spring data JPA?

JPA uses EntityManager interface to create/read/delete operation and maintains the persistence context. Hibernate uses Session interface to create/read/delete operation and maintains the persistence context. JPA uses JPQL (Java Persistence Query Language) as Object Oriented Query language for database operations.


3 Answers

  1. You got LazyInitializationException exactly because you set fetch = Fetch.EAGER. getById() returns a lazily fetched entity and thus the exception.
  2. Just guessing here, but maybe because of the laziness behaviour of getById(). But to be honest I don't understand that either.

It is also important to highlight another detail: findById() method uses EntityManager find(Class<T> entityClass, Object primaryKey, LockModeType lockMode, Map<String,Object> properties)) method internally and getById() uses EntityManager getReference(Class<T> entityClass, Object primaryKey) method. As a consequence, findById() returns the actual object and getById returns a reference of the entity.

Reference documentation:

  • https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#find-java.lang.Class-java.lang.Object-java.util.Map-
  • https://docs.oracle.com/javaee/7/api/javax/persistence/EntityManager.html#getReference-java.lang.Class-java.lang.Object-
like image 62
João Dias Avatar answered Oct 31 '22 16:10

João Dias


Usually we can use either findById or getById. There's no issue in using either of it.

But if we want to understand more specific differences the those differences are as follows:

- getById: This is used only if we are sure about getting an entity we requested from the database. If we don't get any entity, it gives an exception. This is similar to a child who get's whatever it wants but starts screaming if it doesn't get what he requires.

- findById: This is used if we are not sure that whether the requested entity in the database is present or not. So even if the entity is not present in the database it returns null and doesn't throw any exception.

like image 40
RanjeetBorate Avatar answered Oct 31 '22 15:10

RanjeetBorate


getById -> returns a reference proxy to for the actual Entity. Where only the id set (since you already passed it). This object's getters and setters may be called in the same @Transaction. But, once you get out of the transaction, then the proxy will return LazyInitializationException.

getById implementation

if you look at the getReference java doc. I believe this makes all clear. So, hibernate does not hit to the database if you call getById.

Get an instance, whose state may be lazily fetched. If the requested instance does not exist in the database, the EntityNotFoundException is thrown when the instance state is first accessed. (The persistence provider runtime is permitted to throw the EntityNotFoundException when getReference is called.) The application should not expect that the instance state will be available upon detachment, unless it was accessed by the application while the entity manager was open.

on the other hand, findById directly hit to DB and performs the select query.

like image 24
Olgun Kaya Avatar answered Oct 31 '22 14:10

Olgun Kaya