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:
findBy
、existsBy
、deleteBy
and other keywords are delimiters to extract query conditions. - Resolve attribute path: Put the attribute name in the method name (such as
name
) fields mapped to entity class. - Identification operator: by keywords (such as
And
、Or
、LessThan
) 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 nameCriteria
or MongoDB'sQuery
Object.
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:ModelId
andName
is 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@Query
Combining 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.@Query
Or 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 withScenarioField
The attribute names in the class are strictly consistent.
1.2 Implemented Functions
• Operation type: batch deletion.
• Query conditions: Delete allmodelId
Documents whose fields are equal to parameter values.
• Equivalent MongoDB query:
({ modelId: ObjectId("xxx") })
1.3 Use scenarios
• Model cascade deletion: when deleting a model (Model
When ), 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:ObjectId
Make sure to be with MongoDB_id
Type 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
)。
• IdIsNot
:id
The field is not equal to the parameter value (corresponding toid != {id}
)。
• Name
andModelId
: 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 timeid
fornull
, the conditions are simplified toname
andmodelId
)。
• 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` > 0) 2. IdIsNot → Convert to `_id: { $ne: id }` 3. Name → `name = {name}` 4. ModelId → `modelId = {modelId}`
Parameter processing:
- Can be vacant
id
:likeid
fornull
,IdIsNot
Conditions will be ignored and the query is based only onname
andmodelId
。 - Field mapping: Need to ensure
ScenarioField
Entity containsid
、name
、modelId
Properties and match the database field (default camel to underscore).
Performance optimization:
It is recommended to bemodelId
andname
Create 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 as
id
fornull
behavior 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!