Spring Data JPA
What is Spring Data JPA?
Spring Data JPA is part of the Spring Data family. It simplifies data access by providing repository abstractions on top of JPA (Java Persistence API). Instead of writing boilerplate CRUD code, you define an interface and Spring generates the implementation automatically.
package com.example.entity;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Table(name = "users", indexes = {
@Index(name = "idx_email", columnList = "email", unique = true)
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // AUTO_INCREMENT
private Long id;
@Column(name = "username", nullable = false, length = 50, unique = true)
private String username;
@Column(nullable = false)
private String password;
@Column(nullable = false, unique = true)
private String email;
@Enumerated(EnumType.STRING) // Store enum as string in DB
@Column(nullable = false)
private Role role = Role.USER;
@Column(name = "created_at", updatable = false)
private LocalDateTime createdAt;
@Column(name = "updated_at")
private LocalDateTime updatedAt;
@Transient // Not persisted to DB
private String fullDisplayName;
// One user has many orders
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Order> orders;
@PrePersist
protected void onCreate() { createdAt = LocalDateTime.now(); }
@PreUpdate
protected void onUpdate() { updatedAt = LocalDateTime.now(); }
// Constructors, getters, setters...
public enum Role { USER, ADMIN, MODERATOR }
}
package com.example.repository;
import com.example.entity.User;
import org.springframework.data.jpa.repository.*;
import org.springframework.data.domain.*;
import org.springframework.data.repository.query.Param;
import java.util.*;
// JpaRepository provides: save, findById, findAll, delete, count, exists, etc.
public interface UserRepository extends JpaRepository<User, Long> {
// Spring generates query from method name
Optional<User> findByEmail(String email);
Optional<User> findByUsername(String username);
List<User> findByRole(User.Role role);
boolean existsByEmail(String email);
long countByRole(User.Role role);
// Derived query with multiple conditions
List<User> findByRoleAndEmailContaining(User.Role role, String emailPart);
// Custom JPQL query
@Query("SELECT u FROM User u WHERE u.email = :email AND u.role = :role")
Optional<User> findByEmailAndRole(@Param("email") String email,
@Param("role") User.Role role);
// Native SQL query
@Query(value = "SELECT * FROM users WHERE created_at > :date", nativeQuery = true)
List<User> findUsersCreatedAfter(@Param("date") java.time.LocalDateTime date);
// Pagination and sorting
Page<User> findByRole(User.Role role, Pageable pageable);
// Modifying query (UPDATE/DELETE)
@Modifying
@Transactional
@Query("UPDATE User u SET u.password = :password WHERE u.id = :id")
int updatePassword(@Param("id") Long id, @Param("password") String password);
// Delete by field
void deleteByEmail(String email);
}
Service Layer with JPA
@Service
@Transactional
public class UserService {
private final UserRepository userRepository;
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User createUser(User user) {
if (userRepository.existsByEmail(user.getEmail())) {
throw new RuntimeException("Email already exists: " + user.getEmail());
}
return userRepository.save(user);
}
@Transactional(readOnly = true) // Optimization for read-only operations
public User getUserById(Long id) {
return userRepository.findById(id)
.orElseThrow(() -> new RuntimeException("User not found: " + id));
}
@Transactional(readOnly = true)
public Page<User> getUsers(int page, int size, String sortBy) {
Pageable pageable = PageRequest.of(page, size, Sort.by(sortBy).ascending());
return userRepository.findAll(pageable);
}
public User updateUser(Long id, User updatedUser) {
User existing = getUserById(id);
existing.setUsername(updatedUser.getUsername());
existing.setEmail(updatedUser.getEmail());
return userRepository.save(existing); // save() = INSERT or UPDATE
}
public void deleteUser(Long id) {
userRepository.deleteById(id);
}
}
Ready to Level Up Your Skills?
Explore 500+ free tutorials across 20+ languages and frameworks.