Spring Boot - Spring Data JPA
Spring Data JPA eliminates most JPA boilerplate. By extending JpaRepository you get a full set of CRUD operations for free. Custom queries can be added using derived method names or the @Query annotation with JPQL or native SQL.
Contents
Dependency and configuration
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<scope>runtime</scope>
</dependency>
Properties
spring.datasource.url=jdbc:postgresql://localhost:5432/mydb
spring.datasource.username=user
spring.datasource.password=pass
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
Defining an @Entity
@Entity@Id@GeneratedValue
Java
import jakarta.persistence.*;
import java.time.LocalDateTime;
@Entity
@Table(name = "products")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false, length = 200)
private String name;
private Double price;
@Column(name = "created_at")
private LocalDateTime createdAt;
@PrePersist
private void prePersist() {
createdAt = LocalDateTime.now();
}
// Getters and setters
public Long getId() { return id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Double getPrice() { return price; }
public void setPrice(Double price) { this.price = price; }
}
JpaRepository: built-in CRUD
Extend JpaRepository<T, ID>
Java
import org.springframework.data.jpa.repository.JpaRepository;
public interface ProductRepository extends JpaRepository<Product, Long> {
// Built-in: save, findById, findAll, deleteById, count, existsById, etc.
}
Java
@Service
public class ProductService {
private final ProductRepository repo;
public ProductService(ProductRepository repo) { this.repo = repo; }
public Product create(Product p) { return repo.save(p); }
public List<Product> findAll() { return repo.findAll(); }
public void delete(Long id) { repo.deleteById(id); }
public Product findById(Long id) {
return repo.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("Product", id));
}
}
Derived query methods
Spring Data parses method names and generates the JPQL query automatically. Follow the naming convention: findBy[FieldName][Condition]
Java
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByName(String name);
List<Product> findByPriceLessThan(Double maxPrice);
List<Product> findByNameContainingIgnoreCase(String keyword);
Optional<Product> findFirstByOrderByCreatedAtDesc();
boolean existsByName(String name);
}
Custom queries with @Query
Use @Query
Java
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
public interface ProductRepository extends JpaRepository<Product, Long> {
// JPQL
@Query("SELECT p FROM Product p WHERE p.price BETWEEN :min AND :max ORDER BY p.price")
List<Product> findInPriceRange(@Param("min") double min, @Param("max") double max);
// Native SQL
@Query(value = "SELECT * FROM products WHERE name ILIKE %:kw%", nativeQuery = true)
List<Product> searchNative(@Param("kw") String keyword);
// Modifying (UPDATE/DELETE)
@Modifying
@Transactional
@Query("UPDATE Product p SET p.price = p.price * :factor WHERE p.id IN :ids")
int bulkUpdatePrice(@Param("factor") double factor, @Param("ids") List<Long> ids);
}