JPA Persistence

Java Persistence API standard

📊 What is JPA?

Java Persistence API (JPA) is a specification for managing relational data in Java applications. It provides a standard approach for ORM, allowing developers to work with databases using object-oriented programming concepts.


// JPA Repository interface
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByLastName(String lastName);
    User findByEmail(String email);
}
                                    

JPA Core Features

📋

Entity Manager

Manages entity lifecycle and persistence

@PersistenceContext
private EntityManager em;
🔍

JPQL

Java Persistence Query Language

@Query("SELECT u FROM User u WHERE u.age > ?1")
List<User> findUsersOlderThan(int age);
🏪

Repositories

Data access layer abstraction

interface UserRepo extends 
    JpaRepository<User, Long> {}
🔄

Transactions

Automatic transaction management

@Transactional
public void saveUser(User user) {}

🔹 JPA Entity Example

Create a JPA entity with standard annotations:

@Entity
@Table(name = "customers")
public class Customer {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(name = "first_name", nullable = false)
    private String firstName;
    
    @Column(name = "last_name", nullable = false)
    private String lastName;
    
    @Column(name = "email", unique = true)
    private String email;
    
    @Column(name = "phone")
    private String phone;
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "created_at")
    private Date createdAt;
    
    @PrePersist
    protected void onCreate() {
        createdAt = new Date();
    }
    
    // Constructors
    public Customer() {}
    
    public Customer(String firstName, String lastName, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }
    
    // Getters and setters...
}

JPA Features Used:

@Entity - Marks as JPA entity

@PrePersist - Lifecycle callback

@Temporal - Date/time handling

🔹 Spring Data JPA Repository

Create repositories with minimal code:

// Basic repository interface
public interface CustomerRepository extends JpaRepository<Customer, Long> {
    
    // Query methods by naming convention
    List<Customer> findByFirstName(String firstName);
    List<Customer> findByLastNameContaining(String lastName);
    Customer findByEmail(String email);
    List<Customer> findByCreatedAtAfter(Date date);
    
    // Custom JPQL queries
    @Query("SELECT c FROM Customer c WHERE c.firstName = ?1 AND c.lastName = ?2")
    List<Customer> findByFullName(String firstName, String lastName);
    
    @Query("SELECT c FROM Customer c WHERE c.email LIKE %:domain%")
    List<Customer> findByEmailDomain(@Param("domain") String domain);
    
    // Native SQL queries
    @Query(value = "SELECT * FROM customers WHERE phone IS NOT NULL", 
           nativeQuery = true)
    List<Customer> findCustomersWithPhone();
    
    // Modifying queries
    @Modifying
    @Query("UPDATE Customer c SET c.email = :email WHERE c.id = :id")
    int updateCustomerEmail(@Param("id") Long id, @Param("email") String email);
}

🔹 Using JPA Repository

Service layer using JPA repository:

@Service
@Transactional
public class CustomerService {
    
    @Autowired
    private CustomerRepository customerRepository;
    
    // Create
    public Customer saveCustomer(Customer customer) {
        return customerRepository.save(customer);
    }
    
    // Read
    public Optional<Customer> findCustomerById(Long id) {
        return customerRepository.findById(id);
    }
    
    public List<Customer> findAllCustomers() {
        return customerRepository.findAll();
    }
    
    // Update
    public Customer updateCustomer(Customer customer) {
        return customerRepository.save(customer);
    }
    
    // Delete
    public void deleteCustomer(Long id) {
        customerRepository.deleteById(id);
    }
    
    // Custom queries
    public List<Customer> findCustomersByName(String firstName) {
        return customerRepository.findByFirstName(firstName);
    }
    
    public Customer findCustomerByEmail(String email) {
        return customerRepository.findByEmail(email);
    }
}

Benefits:

No SQL code needed

Automatic transaction management

Type-safe queries

🔹 JPA Configuration

Configure JPA in Spring Boot:

# application.properties
spring.datasource.url=jdbc:mysql://localhost:3306/mydb
spring.datasource.username=root
spring.datasource.password=password
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver

# JPA/Hibernate properties
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL8Dialect

# Connection pool
spring.datasource.hikari.maximum-pool-size=20

🔸 Java Configuration

@Configuration
@EnableJpaRepositories(basePackages = "com.example.repository")
public class JpaConfig {
    
    @Bean
    @Primary
    public DataSource dataSource() {
        HikariDataSource dataSource = new HikariDataSource();
        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
        dataSource.setUsername("root");
        dataSource.setPassword("password");
        return dataSource;
    }
}

🧠 Test Your Knowledge

Which interface provides basic CRUD operations in Spring Data JPA?