Why Use JPA ORMs?
Benefits of JPA ORMs
🟢 Simplifies Database Interaction
With JPA, developers can interact with the database using Java objects rather than writing SQL queries, making the code more maintainable and developer-friendly.🟢 Reduced Boilerplate Code
JPA reduces repetitive SQL code, allowing developers to focus on business logic instead of low-level database details.🟢 Strong Typing and Security
By integrating with Java, JPA enforces strong typing, minimizing runtime errors. Parameterized queries are handled internally, reducing the risk of SQL injection attacks.🟢 Community Support
JPA is widely adopted and maintained, ensuring updates, bug fixes, and community-driven support.
🔴Query Limitations
Complex queries involving multiple joins, aggregations, or DB-specific operations may be challenging or inefficient with JPA.🔴Overkill for Small Applications
Small projects may not justify the learning curve and configuration overhead of JPA. JdbcTemplate is more preferable.🔴Vendor Lock-In
JPA abstracts database operations but can limit flexibility if specific DB features need to be utilized.🔴Non-Optimized Queries
Automatically generated queries may not always be performance-optimized, leading to potential inefficiencies.
@GeneratedValue
Specifies the generation strategy for primary key values:AUTO
: Uses the underlying database's strategy.IDENTITY
: Uses the database's auto-increment feature.SEQUENCE
: Leverages a database sequence.TABLE
: Maintains a separate table to store primary keys. Hibernate gets the Id keys from the DB, stores them in hibernate_sequence table and uses it to calculate next Id.
@OneToMany
Defines one-to-many relationships between entities.- Unidirectional: Only one entity is aware of the relationship.
- Bidirectional: Both entities are aware of and can navigate the relationship.
- Cascade options (
PERSIST
,MERGE
, etc.) allow operations to propagate across related entities.
@EmbeddedId
/@Embeddable: Use for composite primary keys.
Cache Mechanisms
First-Level Cache
- Session-scoped, automatically enabled.
- To bypass the cache for large reads, use JPQL or native SQL queries.
Manually Clear Cache:
session.detach(entity); // Detach a specific entity session.clear(); // Clear all entities
Second-Level Cache
- Application-scoped, supports cache providers like EhCache or Redis.
- Ideal for large reads that don’t change frequently.
For projects not leveraging Spring Data JPA, the JPA's EntityManager API is the core tool for database operations.
EntityManager Highlights
- Transactions: You must explicitly manage transactions, while with Spring Data JPA it happens behind the scenes
- Query Language: Supports both JPQL (object-oriented) and native SQL.
Example Configuration (Hibernate + Spring Boot)
Include the spring-boot-starter-data-jpa
dependency, then configure application.properties
:
spring.datasource.url=jdbc:mysql://localhost:3306/my_database spring.datasource.username=root spring.datasource.password=secret spring.jpa.hibernate.ddl-auto=update spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect spring.jpa.show-sql=true
Service using EntityManager and @Transactional:
- With JPA, Spring automatically manages the persistence context (e.g., EntityManager) through dependency injection.
- Here, the container injects the EntityManager in our enterprise components.
In other words, the container creates the EntityManager from the EntityManagerFactory. - EntityManager instances are not thread-safe!
Meaning all instances could interfere with the managed entities, causing issues.
Solution:
Use container-managed EntityManager (like above). Each thread will have its own EntityManager instance with own managed entities set copy. That prevents concurrent issues in persistence context level, like dirty reads or lost updates. Of course, we have to manage concurrency issues in DB level, with e.g. optimistic locking when having @Version, etc.
- @Transactional provides declarative transaction management.
- With JPA, Spring automatically manages the persistence context (e.g., EntityManager) through dependency injection.
- Here, the container injects the EntityManager in our enterprise components.
In other words, the container creates the EntityManager from the EntityManagerFactory. - EntityManager instances are not thread-safe!
Meaning all instances could interfere with the managed entities, causing issues.
Solution:
Use container-managed EntityManager (like above). Each thread will have its own EntityManager instance with own managed entities set copy. That prevents concurrent issues in persistence context level, like dirty reads or lost updates. Of course, we have to manage concurrency issues in DB level, with e.g. optimistic locking when having @Version, etc.
- @Transactional provides declarative transaction management.
Spring Data JPA abstracts away boilerplate repository code and simplifies transaction management.
Core Features
Repositories
Use predefined repository interfaces likeCrudRepository
,JpaRepository
, andPagingAndSortingRepository
to add functionality effortlessly:CrudRepository
: Basic CRUD operations.JpaRepository
: Adds advanced features like flushing persistence contexts and batch deletes.PagingAndSortingRepository
: Supports paging and sorting queries.
Finder Methods
Leverage naming conventions to create query methods, e.g.List<User> findTop3ByNameOrSurnameContainsOrderByName(String searchTerm);
Example Configuration (Spring Data JPA)
Configure repositories by extending one of the predefined interfaces:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByLastName(String lastName);
}
How do Repositories work
Auto-implemented by Spring Data engine. At runtime, concrete class is created using proxies
and reflection. A proxy intercepts calls to @Repository class and then route mostly
to SimpleJpaRepository which has defined query methods from reflection.
Δεν υπάρχουν σχόλια:
Δημοσίευση σχολίου
What may be missing, or could get better?