Spring Data JPA

Simplified database access with powerful repository abstraction

🗄️ What is Spring Data JPA?

Spring Data JPA simplifies database operations by providing repository abstractions and automatic query generation. It reduces boilerplate code and offers powerful features for data access layer implementation.


// Simple repository interface - no implementation needed!
public interface UserRepository extends JpaRepository<User, Long> {
    List<User> findByLastName(String lastName);
    User findByEmail(String email);
}
                                    

Key Features

📚

Repository Pattern

Automatic CRUD operations implementation

extends JpaRepository<Entity, ID>
🔍

Query Methods

Generate queries from method names

findByFirstNameAndLastName()
📝

Custom Queries

Write custom JPQL and native SQL

@Query("SELECT u FROM User u")
📄

Pagination

Built-in pagination and sorting

Pageable pageable

🔹 Entity Definition

Create JPA entities to map database tables:

@Entity
@Table(name = "users")
public class User {
    
    @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(unique = true)
    private String email;
    
    @CreationTimestamp
    private LocalDateTime createdAt;
    
    @UpdateTimestamp
    private LocalDateTime updatedAt;
    
    // Constructors
    public User() {}
    
    public User(String firstName, String lastName, String email) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.email = email;
    }
    
    // Getters and Setters
    public Long getId() { return id; }
    public void setId(Long id) { this.id = id; }
    
    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    
    // ... other getters and setters
}

Database Table:

Creates 'users' table with id, first_name, last_name, email, created_at, updated_at columns

🔹 Repository Interface

Create repository interfaces for data access:

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    
    // Query method - finds users by last name
    List<User> findByLastName(String lastName);
    
    // Query method - finds user by email
    Optional<User> findByEmail(String email);
    
    // Query method - finds users by first name containing
    List<User> findByFirstNameContaining(String firstName);
    
    // Custom JPQL query
    @Query("SELECT u FROM User u WHERE u.firstName = ?1 AND u.lastName = ?2")
    List<User> findByFullName(String firstName, String lastName);
    
    // Native SQL query
    @Query(value = "SELECT * FROM users WHERE email LIKE %?1%", nativeQuery = true)
    List<User> findByEmailPattern(String pattern);
    
    // Count query
    long countByLastName(String lastName);
    
    // Delete query
    void deleteByEmail(String email);
}

Automatic Methods Available:

  • save(entity), saveAll(entities)
  • findById(id), findAll()
  • deleteById(id), delete(entity)
  • count(), existsById(id)

🔹 Service Layer Implementation

Use repositories in service classes:

@Service
@Transactional
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    
    public User createUser(String firstName, String lastName, String email) {
        User user = new User(firstName, lastName, email);
        return userRepository.save(user);
    }
    
    public List<User> getAllUsers() {
        return userRepository.findAll();
    }
    
    public Optional<User> getUserById(Long id) {
        return userRepository.findById(id);
    }
    
    public Optional<User> getUserByEmail(String email) {
        return userRepository.findByEmail(email);
    }
    
    public List<User> getUsersByLastName(String lastName) {
        return userRepository.findByLastName(lastName);
    }
    
    public User updateUser(Long id, String firstName, String lastName) {
        User user = userRepository.findById(id)
            .orElseThrow(() -> new RuntimeException("User not found"));
        
        user.setFirstName(firstName);
        user.setLastName(lastName);
        return userRepository.save(user);
    }
    
    public void deleteUser(Long id) {
        userRepository.deleteById(id);
    }
}

🔹 Pagination and Sorting

Handle large datasets with pagination:

@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @Autowired
    private UserRepository userRepository;
    
    // Paginated results
    @GetMapping
    public Page<User> getUsers(
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size,
            @RequestParam(defaultValue = "id") String sortBy) {
        
        Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy));
        return userRepository.findAll(pageable);
    }
    
    // Sorted results
    @GetMapping("/sorted")
    public List<User> getUsersSorted() {
        Sort sort = Sort.by(Sort.Direction.ASC, "lastName")
                       .and(Sort.by(Sort.Direction.ASC, "firstName"));
        return userRepository.findAll(sort);
    }
}

Response Example:

GET /api/users?page=0&size=5&sortBy=lastName

Returns first 5 users sorted by last name

🔹 Relationships

Define entity relationships:

// One-to-Many relationship
@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
    private List<Employee> employees = new ArrayList<>();
}

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
}

// Repository with relationship queries
public interface EmployeeRepository extends JpaRepository<Employee, Long> {
    List<Employee> findByDepartmentName(String departmentName);
    
    @Query("SELECT e FROM Employee e JOIN e.department d WHERE d.name = ?1")
    List<Employee> findEmployeesByDepartment(String departmentName);
}

🧠 Test Your Knowledge

Which annotation is used to mark a class as a JPA entity?