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);
}