Skip to main content

Quiz: Advanced Spring Data JPA

Test your knowledge of Spring Data JPA, relationships, and queries.

30 questions - Click on each question to reveal the answer.


Questions 1-10: Conventions and Queries​

Question 1: What are Spring Data JPA Query Methods?

Answer: Methods whose name automatically defines the query:

public interface UserRepository extends JpaRepository<User, Long> {
List<User> findByEmail(String email);
List<User> findByLastNameAndFirstName(String ln, String fn);
List<User> findByAgeGreaterThan(int age);
}

Spring automatically generates the SQL implementation.


Question 2: What are common query keywords?

Answer:

KeywordExample
AndfindByNameAndAge
OrfindByNameOrEmail
BetweenfindByAgeBetween
LessThanfindByAgeLessThan
GreaterThanfindByAgeGreaterThan
LikefindByNameLike
ContainingfindByNameContaining
OrderByfindByAgeOrderByNameAsc
NotfindByNameNot
InfindByAgeIn(Collection)
True/FalsefindByActiveTrue

Question 3: How to limit the number of results?

Answer:

// Top/First
User findFirstByOrderByCreatedAtDesc();
List<User> findTop10ByOrderByScoreDesc();

// With Pageable
Page<User> findAll(Pageable pageable);

Question 4: How to write a custom JPQL query?

Answer: With @Query:

@Query("SELECT u FROM User u WHERE u.email LIKE %:domain")
List<User> findByEmailDomain(@Param("domain") String domain);

@Query("SELECT u FROM User u WHERE u.age > :age ORDER BY u.name")
List<User> findOlderThan(@Param("age") int age);

Question 5: How to write a native SQL query?

Answer:

@Query(value = "SELECT * FROM users WHERE email LIKE %?1", nativeQuery = true)
List<User> findByEmailNative(String domain);

@Query(value = "SELECT COUNT(*) FROM users", nativeQuery = true)
long countAllNative();

Question 6: How to perform an update query?

Answer:

@Modifying
@Query("UPDATE User u SET u.active = false WHERE u.lastLogin < :date")
int deactivateInactiveUsers(@Param("date") LocalDate date);

@Modifying
@Query("DELETE FROM User u WHERE u.active = false")
int deleteInactiveUsers();

@Modifying is required for UPDATE/DELETE.


Question 7: How to project only certain fields?

Answer: With projections:

// Interface projection
public interface UserSummary {
String getName();
String getEmail();
}

List<UserSummary> findByActiveTrue();

// DTO projection
@Query("SELECT new com.example.UserDto(u.name, u.email) FROM User u")
List<UserDto> findAllAsDto();

Question 8: How to check for the existence of an entity?

Answer:

boolean existsByEmail(String email);
boolean existsByIdAndActiveTrue(Long id);

// Avoids loading the full entity

Question 9: How to count entities?

Answer:

long countByActiveTrue();
long countByDepartment(String department);

@Query("SELECT COUNT(u) FROM User u WHERE u.age > :age")
long countOlderThan(@Param("age") int age);

Question 10: How to delete by criteria?

Answer:

void deleteByEmail(String email);
long deleteByActivefalse(); // Returns the number deleted

@Modifying
@Query("DELETE FROM User u WHERE u.createdAt < :date")
int deleteOldUsers(@Param("date") LocalDate date);

Questions 11-20: Relationships​

Question 11: How to define a OneToMany relationship?

Answer:

@Entity
public class Department {
@Id
private Long id;

@OneToMany(mappedBy = "department", cascade = CascadeType.ALL)
private List<Employee> employees = new ArrayList<>();
}

@Entity
public class Employee {
@ManyToOne
@JoinColumn(name = "department_id")
private Department department;
}

Question 12: What is mappedBy?

Answer: mappedBy indicates the non-owning side of the relationship. It points to the field in the other entity that owns the foreign key.

@OneToMany(mappedBy = "department")  // "department" is the field in Employee
private List<Employee> employees;

Question 13: How to define a ManyToMany relationship?

Answer:

@Entity
public class Student {
@ManyToMany
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private Set<Course> courses = new HashSet<>();
}

@Entity
public class Course {
@ManyToMany(mappedBy = "courses")
private Set<Student> students = new HashSet<>();
}

Question 14: What is the difference between FetchType.LAZY and EAGER?

Answer:

  • LAZY: loads only when accessed (recommended)
  • EAGER: loads immediately with the parent entity
@OneToMany(fetch = FetchType.LAZY)  // Default for collections
private List<Order> orders;

@ManyToOne(fetch = FetchType.EAGER) // Default for single
private User user;

Question 15: What is the N+1 problem?

Answer: When loading N entities then making N additional queries for the relationships:

// 1 query for departments
List<Department> deps = repo.findAll();

// N queries for employees (1 per department)
deps.forEach(d -> d.getEmployees().size());

Solution: JOIN FETCH or @EntityGraph.


Question 16: How to solve the N+1 problem with JOIN FETCH?

Answer:

@Query("SELECT d FROM Department d JOIN FETCH d.employees")
List<Department> findAllWithEmployees();

A single query loads everything.


Question 17: What is an @EntityGraph?

Answer: Defines which relationships to load:

@EntityGraph(attributePaths = {"employees", "manager"})
List<Department> findAll();

// Or defined on the entity
@NamedEntityGraph(
name = "Department.full",
attributeNodes = @NamedAttributeNode("employees")
)
@Entity
public class Department { }

@EntityGraph("Department.full")
List<Department> findByName(String name);

Question 18: How to handle cascades?

Answer:

@OneToMany(cascade = CascadeType.ALL)  // All operations
@OneToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})

// Types:
// PERSIST - save
// MERGE - update
// REMOVE - delete
// REFRESH - refresh
// DETACH - detach
// ALL - all

Question 19: What is orphanRemoval?

Answer: Automatically deletes orphaned children:

@OneToMany(mappedBy = "parent", orphanRemoval = true)
private List<Child> children;

// If a child is removed from the list, it is deleted from the DB
parent.getChildren().remove(child); // DELETE in DB

Question 20: How to avoid circular references in JSON?

Answer:

// Option 1: @JsonIgnore
@JsonIgnore
@ManyToOne
private Department department;

// Option 2: @JsonManagedReference / @JsonBackReference
@JsonManagedReference
@OneToMany(mappedBy = "department")
private List<Employee> employees;

@JsonBackReference
@ManyToOne
private Department department;

// Option 3: Use DTOs (recommended)

Questions 21-30: Pagination and Performance​

Question 21: How to implement pagination?

Answer:

// Repository
Page<User> findAll(Pageable pageable);
Page<User> findByActiveTrue(Pageable pageable);

// Service
Pageable pageable = PageRequest.of(0, 20, Sort.by("name"));
Page<User> page = userRepository.findAll(pageable);

// Result
page.getContent(); // List
page.getTotalElements(); // Total
page.getTotalPages(); // Number of pages
page.getNumber(); // Current page

Question 22: How to sort results?

Answer:

// By method
List<User> findByActiveOrderByNameAsc(boolean active);

// By Sort parameter
List<User> findByActive(boolean active, Sort sort);
userRepository.findByActive(true, Sort.by("name").descending());

// Multi-criteria
Sort sort = Sort.by("lastName").and(Sort.by("firstName"));

Question 23: How to use Slice instead of Page?

Answer: Slice does not count the total (more efficient):

Slice<User> findByActiveTrue(Pageable pageable);

// Result
slice.getContent();
slice.hasNext(); // Is there a next page?
slice.hasPrevious();
// No getTotalElements() or getTotalPages()

Question 24: How to audit entities (createdAt, updatedAt)?

Answer:

@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public abstract class Auditable {

@CreatedDate
private LocalDateTime createdAt;

@LastModifiedDate
private LocalDateTime updatedAt;

@CreatedBy
private String createdBy;
}

// Enable
@EnableJpaAuditing
@Configuration
public class JpaConfig { }

Question 25: How to implement soft delete?

Answer:

@Entity
@Where(clause = "deleted = false") // Hibernate
public class User {
private boolean deleted = false;
}

// Or with @SQLDelete
@SQLDelete(sql = "UPDATE users SET deleted = true WHERE id = ?")

Question 26: How to optimize queries with indexes?

Answer:

@Entity
@Table(indexes = {
@Index(name = "idx_email", columnList = "email"),
@Index(name = "idx_name_dept", columnList = "lastName, department")
})
public class User { }

Question 27: What is the second-level cache?

Answer: Cache shared between Hibernate sessions:

@Entity
@Cacheable
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Product { }

// Configuration
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=...

Question 28: How to use Specifications for dynamic queries?

Answer:

public interface UserRepository extends JpaSpecificationExecutor<User> { }

// Specification
Specification<User> hasName(String name) {
return (root, query, cb) -> cb.equal(root.get("name"), name);
}

Specification<User> isActive() {
return (root, query, cb) -> cb.isTrue(root.get("active"));
}

// Combination
userRepository.findAll(hasName("John").and(isActive()));

Question 29: How to execute batch queries?

Answer:

// Configuration
spring.jpa.properties.hibernate.jdbc.batch_size=50

// Code
@Transactional
public void saveAll(List<User> users) {
for (int i = 0; i < users.size(); i++) {
entityManager.persist(users.get(i));
if (i % 50 == 0) {
entityManager.flush();
entityManager.clear();
}
}
}

Question 30: How to handle versions for optimistic locking?

Answer:

@Entity
public class Product {
@Version
private Long version;
}

// If two transactions modify simultaneously,
// one throws OptimisticLockException

Score​

ScoreLevel
27-30Excellent - JPA mastered
21-26Good - Some revisions needed
15-20Average - Review the chapters
Less than 15Needs review

Back to Module 6