Pollito Blog
November 25, 2024

Hablemos de Java: Data persistence en Spring

Posted on November 25, 2024  •  5 minutes  • 910 words  • Other languages:  English

¿Quién hace qué?

Hibernate

JPA

Spring Data JPA

Entonces… ¿Quién hace qué?

Spring Boot con JPA

La dependencia spring-boot-starter-data-jpa hace mucho del trabajo pesado por vos, pero hay algunas cositas que vas a tener que considerar para que tu proyecto Spring Boot con JPA y Hibernate funcione sin problemas.

  1. Dependencia a la base de datos: Necesitás un driver de base de datos (H2, MySQL, PostgreSQL, etc.). Spring Boot detecta automáticamente el driver y configura Hibernate con el dialecto apropiado según la base de datos.
  2. Vas a tener que configurar la conexión a la base de datos y algunas propiedades de JPA en application.properties (o application.yml).
  3. Clases Entity.
  4. Interfaces de Repositorio: Vas a necesitar crear una interfaz de repositorio que extienda las interfaces de Spring Data, como JpaRepository.

¿Necesitás algo más?

¿Cuál es el tema con eager/lazy loading?

¿Cuál es la diferencia?

Aspecto Lazy Loading Eager Loading
Definición Los datos asociados se cargan solo cuando se acceden Los datos asociados se cargan inmediatamente junto con la entidad principal
Ventajas Ahorra memoria al no cargar datos innecesarios Simplifica el acceso a datos relacionados sin preocuparse por los límites de la sesión/transacción
Desventajas - Requiere que la sesión de Hibernate esté activa; acceder fuera de ella causa LazyInitializationException. - Puede generar el problema N+1 si se usa mal - Carga datos innecesarios, lo que puede gastar memoria y tiempo de procesamiento. - Puede resultar en consultas grandes y complejas que ralenticen el rendimiento
Caso de uso Ideal para escenarios donde los datos relacionados no se necesitan siempre Ideal para escenarios donde los datos relacionados se requieren siempre
Por defecto en Hibernate LAZY: Para @OneToMany y @ManyToMany EAGER: Para @ManyToOne y @OneToOne

¿Quién se encarga del lazy/eager loading?

Problemas comunes y cómo solucionarlos

LazyInitializationException.

@Transactional
public List<Post> getUserPosts(Long userId) {
    User user = userRepository.findById(userId).orElseThrow();
    return user.getPosts(); // Acceso dentro de la transacción
}

Problema N+1.

@Query("SELECT u FROM User u JOIN FETCH u.posts WHERE u.id = :id")
Optional<User> findUserWithPosts(@Param("id") Long id);
@EntityGraph(attributePaths = {"posts"})
Optional<User> findById(Long id);

Overfetching con eager loading.

Buenas prácticas

  1. Por defecto, usá lazy: Usá FetchType.LAZY a menos que estés 100% seguro de que necesitás los datos siempre.
  2. Ámbito transaccional: Asegurate de acceder a datos lazy dentro de una transacción activa.
  3. Optimizá las consultas: Empleá JOIN FETCH o EntityGraph para casos específicos que requieran datos asociados.
  4. Perfilar y monitorear: Usá herramientas como el logueo SQL de Hibernate o el metamodelo de JPA para monitorear qué consultas se están ejecutando.
  5. Evitá cargar colecciones grandes: Para relaciones de tipo @OneToMany u otras similares, paginá los resultados siempre que sea posible.
Hey, check me out!

You can find me here