skip to content

What is Query by Example (QBE) in Spring Data, and what are the three building blocks?

level: juniorimportance: must knowfreq 55%

answer

  1. Probe + ExampleMatcher + Example
  2. non-null fields become WHERE by default
  3. QueryByExampleExecutor.findAll(Example)
  4. no ranges / no BETWEEN / no OR-across-fields
  5. primitives can't be null — must ignore

basics

~20 s

Query by Example lets you search by filling in a sample entity (a 'probe'). Spring turns the non-null fields into a WHERE clause. The three parts are: Probe (the sample entity), ExampleMatcher (matching rules), and Example (probe + matcher combined).

solid answer

~40 s

Query by Example is a Spring Data feature for building queries dynamically without writing JPQL or method names. You create a 'probe' — an instance of your entity with only the fields you want to match populated. You wrap it in an Example (Example.of(probe) or Example.of(probe, matcher)) and pass it to repository methods inherited from QueryByExampleExecutor, such as findAll(Example), findOne(Example), or count(Example). By default only non-null properties become predicates, joined with AND, using exact equality. An ExampleMatcher customizes this: which properties to ignore, string matching mode (contains, starts-with), case sensitivity, and whether to AND or OR the predicates. It's ideal for simple, uniform search forms but can't express ranges, OR across arbitrary fields, or nested traversals well.

code

java · 15 lines
java
// Repository just extends the standard interfaces
public interface PersonRepository
        extends JpaRepository<Person, Long> { } // JpaRepository extends QueryByExampleExecutor

// 1. Probe: a sample entity with only the fields we care about
Person probe = new Person();
probe.setLastName("Smith");
probe.setCity("Berlin");

// 2. Example wraps the probe (default matcher: non-null props, AND, exact)
Example<Person> example = Example.of(probe);

// 3. Query
List<Person> results = personRepository.findAll(example);
long count = personRepository.count(example);

go deeper

for a junior

Should know the three parts (probe, matcher, Example) and that non-null fields become the filter.

for a middle

Should know the primitive gotcha and the exact repository methods, plus default AND/exact-match behavior.

for a senior

Should articulate the LIKE/equality-only limitation and when to reach for Querydsl/Specifications instead.

for a principal

Frames QBE as one of several dynamic-query strategies, weighing refactor-safety vs expressiveness for team-wide search patterns.

**Query by Example (QBE)** is a query technique in Spring Data (interface `QueryByExampleExecutor<T>`, which `JpaRepository` extends) that lets you build a query from a *sample instance* of your domain object instead of writing JPQL, a derived method name, or a `@Query`. **The three building blocks:** 1. **Probe** — an actual instance of your entity class where you set only the fields you want to filter on. Example: `Person probe = new Person(); probe.setLastName("Smith");`. Fields left `null` are ignored by default (for primitives, which can't be null, you must explicitly ignore their paths or they'll always be part of the query with their default value like `0` or `false` — a classic gotcha). 2. **ExampleMatcher** — an immutable configuration object (`org.springframework.data.domain.ExampleMatcher`) describing *how* to match: which paths to ignore, string-matching strategy, case sensitivity, null handling, and AND vs OR. Created via `ExampleMatcher.matching()` (all predicates ANDed), `matchingAll()`, or `matchingAny()` (ORed). 3. **Example** — `org.springframework.data.domain.Example<T>`, which pairs a probe with a matcher. `Example.of(probe)` uses the default matcher; `Example.of(probe, matcher)` uses a custom one. **How it executes:** Spring introspects the probe, reads each property's value, and for every non-ignored, non-null property emits a predicate. It combines them per the matcher (AND/OR) and translates to the underlying store query (JPA Criteria for JPA, a query document for MongoDB, etc.). **Repository methods** (from `QueryByExampleExecutor`): `findOne(Example)`, `findAll(Example)`, `findAll(Example, Sort)`, `findAll(Example, Pageable)`, `count(Example)`, `exists(Example)`, and the fluent `findBy(Example, queryFunction)`. **Strengths:** No query strings, refactor-safe, great for dynamic search forms where the shape of the query varies by which fields the user filled in. **Limitations:** Only supports equality-style and string predicates (`=`, `LIKE`); cannot express `<`, `>`, `BETWEEN`, `IN` with a collection, negation, or OR across *different* firing conditions cleanly; nested/associated property matching is limited; regex/like is only on the outermost property level. For richer dynamic queries use Querydsl or Specifications.

  • Why are primitive fields a common QBE gotcha?
    Primitives (int, boolean, long) can't be null, so they always hold a default value (0, false). QBE includes them in the query by default, silently adding predicates like `age = 0`. You must call matcher.withIgnorePaths("age") or use boxed types.
  • Which repository interface provides QBE methods?
    org.springframework.data.repository.query.QueryByExampleExecutor<T>. JpaRepository (and Mongo/etc. repositories) extend it, so findAll(Example), findOne(Example), count(Example), exists(Example) are available automatically.

saying these in an interview costs you the question

  • Thinking QBE can express ranges like age > 18 or BETWEEN
  • Believing null fields are matched as 'IS NULL' by default (they're ignored)
  • Forgetting primitive fields silently add predicates
  • Confusing Example (the wrapper) with ExampleMatcher (the rules)

context