SoFunction
Updated on 2025-04-13

Implementation of spring's data derived query mechanism

Spring Data's Derived Query is a mechanism that automatically generates database queries through method name conventions, without manually writing SQL or JPQL. The following is a detailed analysis of its core principles and usage:

1. Core mechanism

1. Method name resolution rules

Spring Data parses out the query logic based on the structure of the method name and generates the corresponding database query.
Key steps:

  • Split method name:findByexistsBydeleteByand other keywords are delimiters to extract query conditions.
  • Resolve attribute path: Put the attribute name in the method name (such asname) fields mapped to entity class.
  • Identification operator: by keywords (such asAndOrLessThan) Determine the relationship and operation of query conditions.

2. Dynamic proxy implementation

• Interface Agent: Spring Data generates dynamic proxy classes for the Repository interface at runtime.
• Query construction: Generate the corresponding one based on the method nameCriteriaor MongoDB'sQueryObject.

2. Method naming specifications

1. Method prefix

Prefix effect Example
findBy Query and return the result findByName(String name)
existsBy Check if there is a record existsByEmail(String email)
deleteBy Delete records that meet the criteria deleteByStatus(Status status)
countBy Statistics the number of records that meet the criteria countByAgeGreaterThan(int age)

2. Conditional keywords

Keywords Operator Example
And AND Connect multiple conditions findByNameAndAge
Or OR Connect multiple conditions findByNameOrEmail
Is/Equals Equal to (=) findByEmailIs
LessThan Less than (<) findByAgeLessThan
Like Fuzzy match (%value%) findByNameLike
Null/NotNull Field is empty/non-empty findByDescriptionNull

3. Special syntax

• Ignore case:findByNameIgnoreCase•Sort:findByOrderByNameAsc•Pagination:findByName(String name, Pageable pageable)

3. Implementation principle (taking MongoDB as an example)

1. Conversion from method name to query

Assuming the definition method:

fun findByModelIdAndName(modelId: ObjectId, name: String): List<ScenarioField>

Generation logic:

Analysis conditions:ModelIdandNameis an entity field.

Build query:

({
  modelId: ObjectId("xxx"),
  name: "xxx"
})

2. Complex query example

fun existsByIdIsNotAndNameAndModelId(id: ObjectId?, name: String, modelId: ObjectId): Boolean

Converted MongoDB query:

({
  name: "xxx",
  modelId: ObjectId("xxx"),
  _id: { $ne: ObjectId("xxx") }  // When id is not empty})

4. Advanced usage

1. Nested property query

If the entity contains nested objectsUser, you can query nested fields:

interface UserRepository : MongoRepository<User, ObjectId> {
    fun findByAddressCity(city: String): List<User>
}

Corresponding entities:

data class User(
    val name: String,
    val address: Address
)

data class Address(
    val city: String,
    val street: String
)

2. Custom return type

Supports return some fields or DTO projections:

interface UserRepository : MongoRepository<User, ObjectId> {
    fun findNameByEmail(email: String): String
}

3. Combination annotation query

and@QueryCombining annotations to deal with complex logic:

@Query("{'modelId': ?0, 'status': { \$in: ?1 }}")
fun findByModelIdAndStatusIn(modelId: ObjectId, statuses: List<Status>): List<ScenarioField>

V. Best Practices and Limitations

1. Applicable scenarios

Simple query: Quickly implement CRUD operations.
Dynamic conditions: Flexible combination of conditions through method names.
Rapid prototyping: Reduce boilerplate code.

2. Limitations

Complex query: Multi-table association and aggregation operations need to be written manually.@Query
Naming verbose: Deep nesting properties may cause method names to be too long.
Performance Trap: Complex conditions can affect performance when indexes are not optimized.

3. Debugging skills

Turn on log: View generated query statements:

=DEBUG

Verification method name: Ensure that the attribute name strictly matches the entity field.

6. Summary

Spring Data's derived query mechanism converts method names into database queries through conventions that are better than configuration. Its core value lies in:

  • Simplify development: Reduce the workload of manually writing queries.
  • Improve readability: The method name directly reflects the business logic.
  • Type safety: Check the legality of attribute names during compilation.

Rational use of derived queries can significantly improve development efficiency, but it needs to be combined in complex scenarios.@QueryOr customize to achieve flexible response.

Examples are as follows:

Methods deleteAllByModelId and existsByIdIsNotAndNameAndModelId Detailed explanation

1. deleteAllByModelId(modelId: ObjectId)

1.1 Definition basis

• The Spring Data derived query mechanism is based on the method name naming rules. Spring Data MongoDB automatically parses the method name and generates corresponding deletion operations.
• deleteAllBy: Indicates deletion of all documents that meet the criteria.
• ModelId: Map to entity fieldsmodelId, need to be withScenarioFieldThe attribute names in the class are strictly consistent.

1.2 Implemented Functions

• Operation type: batch deletion.
• Query conditions: Delete allmodelIdDocuments whose fields are equal to parameter values.
• Equivalent MongoDB query:

({ modelId: ObjectId("xxx") })

1.3 Use scenarios

• Model cascade deletion: when deleting a model (ModelWhen ), clean up all the scene items associated with it simultaneously (ScenarioField)。
• Data maintenance: batch cleaning of invalid or test data.

1.4 Technical details

• Method name resolution process:

1. deleteAllBy → Delete operation(correspond `deleteMany`)  
2. ModelId → Conditional field name `modelId`  

• Parameter type matching:ObjectIdMake sure to be with MongoDB_idType compatible.
• Transactional: If there is a parent class or method@Transactional, the operation will be executed in a transaction.

2. existsByIdIsNotAndNameAndModelId(id: ObjectId?, name:String, modelId: ObjectId): Boolean

2.1 Definition basis

• Spring Data derived query rules dynamically generate query logic through conditional expressions in method names:
• existsBy: Check whether there are documents that meet the criteria (returntrue/false)。
• IdIsNotidThe field is not equal to the parameter value (corresponding toid != {id})。
• NameandModelId: The field is equal to the parameter value (corresponding toname = {name}andmodelId = {modelId})。

2.2 Implemented Functions

• Operation type: Existence check.
• Query conditions:

WHERE name = {name} 
  AND modelId = {modelId} 
  AND id != {id} (if id Not empty)

• Equivalent MongoDB query:

({
  name: "xxx",
  modelId: ObjectId("xxx"),
  _id: { $ne: ObjectId("xxx") } // When id is not empty})

2.3 Use scenarios

• Uniqueness verification:
• Added scene item: Check whether the same name item exists under the same model (at this timeidfornull, the conditions are simplified tonameandmodelId)。
• Updated scene items: Make sure that the modified name does not duplicate other items under the same model (exclude yourselfid)。

2.4 Technical details

• Method name resolution process:

1. existsBy → Existence check(correspond `count` &gt; 0)  
2. IdIsNot → Convert to `_id: { $ne: id }`  
3. Name → `name = {name}`  
4. ModelId → `modelId = {modelId}`  

Parameter processing:

  • Can be vacantid:likeidfornullIdIsNotConditions will be ignored and the query is based only onnameandmodelId
  • Field mapping: Need to ensureScenarioFieldEntity containsidnamemodelIdProperties and match the database field (default camel to underscore).

Performance optimization:
It is recommended to bemodelIdandnameCreate a composite index on to speed up query:

({ modelId: 1, name: 1 })

3. Complete code examples and verification

3.1 Entity Definition

@Document(collection = "scenarioField")
data class ScenarioField(
    @Id
    val id: ObjectId? = null,
    val name: String,
    val modelId: ObjectId
)

3.2 Test cases

// Test existential check (new scenario)fun testExistsForCreate() {
    val modelId = ObjectId()
    (ScenarioField(name = "Field1", modelId = modelId))
    
    val exists = (null, "Field1", modelId)
    assertTrue(exists) // Should return true}

// Test existential check (update scenario)fun testExistsForUpdate() {
    val modelId = ObjectId()
    val field = (ScenarioField(name = "Field1", modelId = modelId))
    
    // Try to modify it to the same name    val exists = (, "Field1", modelId)
    assertFalse(exists) // should return false (only matched by itself)}

// Test batch deletionfun testDeleteByModelId() {
    val modelId = ObjectId()
    (ScenarioField(name = "Field1", modelId = modelId))
    (ScenarioField(name = "Field2", modelId = modelId))
    
    (modelId)
    val count = (modelId)
    assertEquals(0, count)
}

4. Summary

method Core role Technology implementation Business scenarios
deleteAllByModelId Delete scene items in batches by model ID Spring Data derived query generation deleteMany Clean up associated data when model is deleted
existsByIdIsNotAndNameAndModelId Verify the uniqueness of names under the same model (exclude itself) Dynamically generate $ne and equivalent conditions Prevent data duplication when adding/updating

Spring Data Advantages: Reduce handwritten query code through method name conventions and improve development efficiency.

Notes:

  • Strictly follow naming rules to avoid misspelling field names.
  • Index high-frequency query fields to optimize performance.
  • The nullable parameters need to handle boundary conditions in the business logic (such asidfornullbehavior when  ).

This is the end of this article about the implementation of the data derived query mechanism of spring. For more related spring data derived query content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!