Chapter 1: Advanced Naming Conventions
Introduction
In Module 2, you learned 3 simple keywords: findBy, And, Or.
Now, you will learn 15+ additional keywords to create complex queries!
What You Will Learn
- The 15+ Spring Data JPA keywords
- How to combine them
- Examples for each keyword
Duration: 1h
How Does It Work?
The Magic Principle of Spring Data JPA
public interface ProductRepository extends JpaRepository<Product, Long> {
List<Product> findByPriceLessThan(Double maxPrice);
// ^^^^^^ ^^^^^ ^^^^^^^
// find By PriceLessThan
}
Spring reads the method name and generates the SQL automatically!
-- Automatically generated SQL:
SELECT * FROM product WHERE price < ?
You do NOT write SQL, Spring does it for you!
Method Name Structure
findBy + [Field] + [Operation] + [OtherField] + [Operation]
Examples:
findByName // WHERE name = ?
findByPriceLessThan // WHERE price < ?
findByNameAndPrice // WHERE name = ? AND price = ?
findByPriceBetween // WHERE price BETWEEN ? AND ?
The 15+ Keywords
1. And / Or (You Already Know)
Combine multiple conditions:
// AND
List<Product> findByNameAndPrice(String name, Double price);
// SQL: WHERE name = ? AND price = ?
// OR
List<Product> findByNameOrCategory(String name, String category);
// SQL: WHERE name = ? OR category = ?
Concrete example:
// Find a "Laptop" product at €999.99
productRepo.findByNameAndPrice("Laptop", 999.99);
2. Between (Between two values)
Find values within a range:
List<Product> findByPriceBetween(Double min, Double max);
// SQL: WHERE price BETWEEN ? AND ?
Example:
// Products between €100 and €500
List<Product> products = productRepo.findByPriceBetween(100.0, 500.0);
Use cases:
- Price within a range
- Dates between two moments
- Ages between min and max
3. LessThan / GreaterThan (Comparisons)
Compare numeric values or dates:
// Less than
List<Product> findByPriceLessThan(Double maxPrice);
// SQL: WHERE price < ?
// Less than or equal
List<Product> findByPriceLessThanEqual(Double maxPrice);
// SQL: WHERE price <= ?
// Greater than
List<Product> findByPriceGreaterThan(Double minPrice);
// SQL: WHERE price > ?
// Greater than or equal
List<Product> findByPriceGreaterThanEqual(Double minPrice);
// SQL: WHERE price >= ?
Examples:
// Products less than €100
productRepo.findByPriceLessThan(100.0);
// Products €100 or less
productRepo.findByPriceLessThanEqual(100.0);
// Products more than €1000
productRepo.findByPriceGreaterThan(1000.0);
Use cases:
- Min/max price
- Minimum stock
- Minimum/maximum age
- Dates before/after
4. Like / Containing / StartingWith / EndingWith (Text Search)
Search within strings:
// LIKE (you provide the %)
List<Product> findByNameLike(String pattern);
// SQL: WHERE name LIKE ?
// Usage: findByNameLike("%Laptop%")
// CONTAINING (Spring adds the % automatically)
List<Product> findByNameContaining(String keyword);
// SQL: WHERE name LIKE ?
// Usage: findByNameContaining("Laptop")
// Searches: %Laptop%
// STARTING WITH (searches at the beginning)
List<Product> findByNameStartingWith(String prefix);
// SQL: WHERE name LIKE ?
// Usage: findByNameStartingWith("Mac")
// Searches: Mac%
// ENDING WITH (searches at the end)
List<Product> findByNameEndingWith(String suffix);
// SQL: WHERE name LIKE ?
// Usage: findByNameEndingWith("Pro")
// Searches: %Pro
Examples:
// Products containing "phone" (iPhone, smartphone, etc.)
productRepo.findByNameContaining("phone");
// Products starting with "Mac" (MacBook, Mac Mini, etc.)
productRepo.findByNameStartingWith("Mac");
// Products ending with "Pro" (MacBook Pro, iPad Pro, etc.)
productRepo.findByNameEndingWith("Pro");
Difference Like vs Containing:
// Like - you control the %
findByNameLike("%Laptop%") // Contains Laptop
findByNameLike("Laptop%") // Starts with Laptop
findByNameLike("%Laptop") // Ends with Laptop
// Containing - Spring adds the %
findByNameContaining("Laptop") // Contains Laptop (%Laptop%)
5. In / NotIn (In a list)
Check if a value is in a list:
// IN
List<Product> findByCategoryIn(List<String> categories);
// SQL: WHERE category IN (?, ?, ?)
// NOT IN
List<Product> findByCategoryNotIn(List<String> categories);
// SQL: WHERE category NOT IN (?, ?, ?)
Examples:
// Products in multiple categories
List<String> categories = Arrays.asList("Electronics", "Computers", "Phones");
productRepo.findByCategoryIn(categories);
// Products NOT in these categories
productRepo.findByCategoryNotIn(categories);
Use cases:
- Filter by multiple categories
- Exclude certain statuses
- Search by multiple IDs
6. IsNull / IsNotNull (Null values)
Check if a field is null:
// IS NULL
List<Product> findByDiscountIsNull();
// SQL: WHERE discount IS NULL
// IS NOT NULL (or NotNull)
List<Product> findByDiscountIsNotNull();
List<Product> findByDiscountNotNull();
// SQL: WHERE discount IS NOT NULL
Examples:
// Products without discount
productRepo.findByDiscountIsNull();
// Products with a discount
productRepo.findByDiscountIsNotNull();
Use cases:
- Products without image
- Orders without delivery date
- Users without email
7. True / False (Booleans)
Check boolean values:
// TRUE
List<Product> findByActiveTrue();
// SQL: WHERE active = true
// FALSE
List<Product> findByActiveFalse();
// SQL: WHERE active = false
Examples:
// Active products
productRepo.findByActiveTrue();
// Inactive products
productRepo.findByActiveFalse();
Use cases:
- Active/inactive products
- Verified/unverified users
- Paid/unpaid orders
8. IgnoreCase (Ignore case)
Case-insensitive search:
// Single field
List<Product> findByNameIgnoreCase(String name);
// SQL: WHERE UPPER(name) = UPPER(?)
// Multiple fields
List<Product> findByNameAndCategoryAllIgnoreCase(String name, String category);
// SQL: WHERE UPPER(name) = UPPER(?) AND UPPER(category) = UPPER(?)
Examples:
// Finds "laptop", "LAPTOP", "Laptop", etc.
productRepo.findByNameIgnoreCase("laptop");
Use cases:
- User search (case-insensitive)
- Product search
- Email (john@email.com = JOHN@email.com)
9. OrderBy (Sorting)
Sort results:
// Ascending order
List<Product> findByCategoryOrderByPriceAsc(String category);
// SQL: WHERE category = ? ORDER BY price ASC
// Descending order
List<Product> findByCategoryOrderByPriceDesc(String category);
// SQL: WHERE category = ? ORDER BY price DESC
// Multiple sorting
List<Product> findByCategoryOrderByPriceAscNameDesc(String category);
// SQL: WHERE category = ? ORDER BY price ASC, name DESC
Examples:
// Laptops from cheapest to most expensive
productRepo.findByCategoryOrderByPriceAsc("Laptops");
// Laptops from most expensive to cheapest
productRepo.findByCategoryOrderByPriceDesc("Laptops");
Powerful Combinations
Example 1: Complex E-commerce Search
public interface ProductRepository extends JpaRepository<Product, Long> {
// Active products, within a price range, sorted by name
List<Product> findByActiveTrueAndPriceBetweenOrderByNameAsc(
Double minPrice,
Double maxPrice
);
// SQL: WHERE active = true
// AND price BETWEEN ? AND ?
// ORDER BY name ASC
}
Usage:
// Active products between €100 and €500, sorted by name
productRepo.findByActiveTrueAndPriceBetweenOrderByNameAsc(100.0, 500.0);
Example 2: Stock Management
public interface ProductRepository extends JpaRepository<Product, Long> {
// Out of stock products in a category
List<Product> findByCategoryAndStockLessThan(String category, Integer minStock);
// SQL: WHERE category = ? AND stock < ?
// Products with available stock, excluding certain categories
List<Product> findByStockGreaterThanAndCategoryNotIn(
Integer minStock,
List<String> excludedCategories
);
// SQL: WHERE stock > ? AND category NOT IN (?, ?, ?)
}
Example 3: User Search
public interface UserRepository extends JpaRepository<User, Long> {
// Active users with verified email
List<User> findByActiveTrueAndEmailVerifiedTrue();
// Users created within a period
List<User> findByCreatedAtBetween(LocalDate start, LocalDate end);
// Users with name containing a keyword (case-insensitive)
List<User> findByNameContainingIgnoreCase(String keyword);
}
Summary Table of the 15+ Keywords
| Keyword | Syntax | SQL | Usage |
|---|---|---|---|
| And | findByNameAndPrice | WHERE name = ? AND price = ? | Combine conditions |
| Or | findByNameOrCategory | WHERE name = ? OR category = ? | Alternative |
| Between | findByPriceBetween | WHERE price BETWEEN ? AND ? | Range |
| LessThan | findByPriceLessThan | WHERE price < ? | Less than |
| LessThanEqual | findByPriceLessThanEqual | WHERE price <= ? | Less than or equal |
| GreaterThan | findByPriceGreaterThan | WHERE price > ? | Greater than |
| GreaterThanEqual | findByPriceGreaterThanEqual | WHERE price >= ? | Greater than or equal |
| Like | findByNameLike | WHERE name LIKE ? | Pattern with % |
| Containing | findByNameContaining | WHERE name LIKE %?% | Contains |
| StartingWith | findByNameStartingWith | WHERE name LIKE ?% | Starts with |
| EndingWith | findByNameEndingWith | WHERE name LIKE %? | Ends with |
| In | findByCategoryIn | WHERE category IN (?) | In list |
| NotIn | findByCategoryNotIn | WHERE category NOT IN (?) | Not in list |
| IsNull | findByDiscountIsNull | WHERE discount IS NULL | Is null |
| IsNotNull | findByDiscountIsNotNull | WHERE discount IS NOT NULL | Is not null |
| True | findByActiveTrue | WHERE active = true | True |
| False | findByActiveFalse | WHERE active = false | False |
| IgnoreCase | findByNameIgnoreCase | WHERE UPPER(name) = UPPER(?) | Case-insensitive |
| OrderBy | findByOrderByPriceAsc | ORDER BY price ASC | Sorting |
Tips and Best Practices
1. Readable Method Names
✅ GOOD:
findByPriceBetweenAndCategoryOrderByNameAsc
- Readable
- Clear
- Follows conventions
❌ BAD:
findByPAndC // Too short
findProductsWherePriceIsBetweenMinAndMaxAndCategoryEqualsGivenCategoryOrderedByName // Too long
2. Limit Complexity
If the method becomes too complex, use @Query:
// ❌ Too complex
findByActiveTrueAndPriceBetweenAndCategoryInAndStockGreaterThanAndNameContainingOrderByPriceAscNameDesc
// ✅ Use @Query instead
@Query("SELECT p FROM Product p WHERE p.active = true AND ...")
List<Product> findComplexQuery(...);
3. Test the Methods
@Test
public void testFindByPriceBetween() {
// Arrange
productRepo.save(new Product("Cheap", 50.0));
productRepo.save(new Product("Medium", 150.0));
productRepo.save(new Product("Expensive", 500.0));
// Act
List<Product> results = productRepo.findByPriceBetween(100.0, 200.0);
// Assert
assertEquals(1, results.size());
assertEquals("Medium", results.get(0).getName());
}
Chapter Summary
What You Have Learned
✅ 15+ keywords to create queries
✅ Combinations of keywords
✅ Text search (Like, Containing, etc.)
✅ Comparisons (LessThan, GreaterThan, Between)
✅ Lists (In, NotIn)
✅ Null (IsNull, IsNotNull)
✅ Booleans (True, False)
✅ Sorting (OrderBy)
Now You Can
// Create complex queries without SQL!
List<Product> findByActiveTrueAndPriceBetweenAndCategoryInOrderByPriceAsc(
Double min,
Double max,
List<String> categories
);
Self-Assessment
Mentally create the method for:
- Finding products between €100 and €500
- Finding products containing "phone" in the name
- Finding active products with stock > 10
- Finding users created after a date
- Finding unpaid orders
Answers:
findByPriceBetween(Double min, Double max)findByNameContaining(String keyword)findByActiveTrueAndStockGreaterThan(Integer minStock)findByCreatedAtAfter(LocalDate date)findByPaidFalse()
Next Step
You master naming conventions! Move on to Entity Relationships.