Working with Spring Data JPA

1. Configuring Data Source Properties

Property Description
spring.datasource.url JDBC URL
spring.datasource.username/password Credentials
spring.datasource.driver-class-name Optional (auto-detect)
spring.datasource.hikari.maximum-pool-size HikariCP max conn
spring.jpa.hibernate.ddl-auto none/validate/update/create/create-drop
spring.jpa.show-sql Log SQL (use logging.level.org.hibernate.SQL=DEBUG in prod)
spring.jpa.open-in-view Set false in services

2. Creating Entity Classes (@Entity, @Table)

Example: JPA entity with index and audit timestamps

@Entity
@Table(name="orders", indexes=@Index(columnList="customer_id,status"))
public class Order {
  @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private Long id;
  @Column(nullable=false) private String reference;
  @Enumerated(EnumType.STRING) private OrderStatus status;
  @Column(name="customer_id") private Long customerId;
  @CreationTimestamp private Instant createdAt;
  // getters/setters/protected no-arg ctor
}

3. Defining Primary Keys

Strategy Behavior
IDENTITY DB autoincrement; one INSERT per save
SEQUENCE Uses DB sequence; supports batching
TABLE Portable but slower
UUID Java/DB-side generated UUID
AUTO Provider-chosen

4. Mapping Columns (@Column annotations)

Attribute Use
name DB column name
nullable Default true
unique Adds unique constraint at DDL
length VARCHAR size
precision/scale Numeric
insertable/updatable Read-only fields
columnDefinition Raw DDL fragment

5. Defining Relationships

Annotation Cardinality Default Fetch
@OneToOne 1:1 EAGER
@OneToMany 1:N LAZY
@ManyToOne N:1 EAGER (override to LAZY)
@ManyToMany M:N LAZY

6. Creating Repository Interfaces

Example: Repository with derived query methods

public interface OrderRepository extends JpaRepository<Order, Long> {
  Optional<Order> findByReference(String reference);
  List<Order> findByStatusAndCustomerId(OrderStatus s, Long customerId);
  long countByStatus(OrderStatus status);
}
Interface Provides
Repository<T,ID> Marker only
CrudRepository CRUD
PagingAndSortingRepository +Page/Sort
JpaRepository +flush, batch, getReferenceById
ListCrudRepository List instead of Iterable

7. Using Derived Query Methods

Keyword SQL
findBy / readBy / queryBy SELECT
findFirst10ByOrderByCreatedAtDesc LIMIT + ORDER BY
findByEmailContainingIgnoreCase LIKE
findByAgeBetween BETWEEN
findByStatusIn IN
existsBy / countBy / deleteBy EXISTS / COUNT / DELETE

8. Writing Custom JPQL Queries (@Query)

Example: Custom JPQL select and update queries

public interface OrderRepository extends JpaRepository<Order, Long> {
  @Query("select o from Order o where o.status = :s and o.total > :min")
  List<Order> findHighValue(@Param("s") OrderStatus s, @Param("min") BigDecimal min);

  @Modifying
  @Query("update Order o set o.status='CANCELLED' where o.id = :id")
  int cancel(@Param("id") Long id);
}

9. Using Native SQL Queries

Example: Native query with interface projection

@Query(value = "SELECT * FROM orders WHERE created_at > ?1",
       nativeQuery = true)
List<Order> recent(Instant since);

// Projection via interface
public interface OrderSummary { String getReference(); BigDecimal getTotal(); }
@Query(value="SELECT reference, total FROM orders", nativeQuery=true)
List<OrderSummary> summaries();

10. Implementing Pagination (Pageable, Page<T>)

Example: Paginate with sort

Page<Order> page = repo.findAll(PageRequest.of(0, 20, Sort.by("createdAt").descending()));
page.getTotalElements();
page.getContent();
Type Use
Page<T> Content + total count (extra COUNT query)
Slice<T> Content + hasNext (no count)
Window<T> Keyset pagination (Spring Data 3)

11. Implementing Sorting

API Example
Sort.by(...) Sort.by("name").ascending()
Multiple Sort.by(Order.desc("ts"), Order.asc("id"))
Method param List<X> findAll(Sort sort);

12. Using Query by Example

Example: Query by example with null ignore

Order probe = new Order();
probe.setStatus(OrderStatus.PENDING);
ExampleMatcher matcher = ExampleMatcher.matchingAll().withIgnoreNullValues();
List<Order> results = repo.findAll(Example.of(probe, matcher));

13. Using Specifications for Dynamic Queries

Example: Dynamic query with Specification

public class OrderSpecs {
  public static Specification<Order> status(OrderStatus s) {
    return (root, q, cb) -> cb.equal(root.get("status"), s);
  }
  public static Specification<Order> minTotal(BigDecimal min) {
    return (root, q, cb) -> cb.greaterThanOrEqualTo(root.get("total"), min);
  }
}
// Usage
repo.findAll(where(status(PENDING)).and(minTotal(BigDecimal.TEN)));
Note: Repository must extend JpaSpecificationExecutor<T>.