Spring Data Jpa Named Queries

Spring Data Jpa provides a convenient way to create methods to generate query the underlying database. But in some situations it's not possible to create a query by using a method name or JPA doesn't support the keyword or the method name gets way to much big. To handle these scenarios, Spring Data Jpa provides named queries.

Spring Data Jpa provides 2 ways to handle named queries. XML based and Annotation-based. The annotation-based configuration has an advantage over XML based named queries. XML based named queries need another configuration file to be edited and maintained. In Annotation-based configuration, it has the advantage of low maintenance and recompiles the domain class for every newly named query declaration.

Spring Data JPA Repositories tries to relate the Named query with the matching method name. @Named Query must start with the domain class, followed by a dot and then method name. If Spring Data Jpa is unable to find the matching method name, it will try to create a new query from the method name.

drop database if exists AppleDb;
create database AppleDb;
use AppleDb;
CREATE TABLE apple ( apple_id BIGINT NOT NULL, apple_name VARCHAR(255) DEFAULT NULL, taste VARCHAR(255) DEFAULT NULL, PRIMARY KEY (apple_id)) ENGINE=INNODB;
CREATE TABLE hibernate_sequence ( next_val BIGINT) ENGINE=INNODB;
insert into hibernate_sequence values ( 1 );
insert into apple (apple_name, apple_id, taste) values ("Macintosh", 1, "tangy");
insert into apple (apple_name, apple_id, taste) values ("Fuji", 2, "sweet");
insert into apple (apple_name, apple_id, taste) values ("Gala", 3, "juicy");
insert into apple (apple_name, apple_id, taste) values ("Jonagold", 4, "sweet");
insert into apple (apple_name, apple_id, taste) values ("GrannySmith", 5, "sharp");
package com.sujan.example.jpa.controller;

import com.sujan.example.jpa.entity.Apple;
import com.sujan.example.jpa.repository.AppleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
public class AppleController {
    @Autowired
    private AppleRepository appleRepository;

    @GetMapping
    void namedQuery() {
        Apple findByAppleName = appleRepository.findByAppleName("Macintosh");
        System.out.println("findByAppleName = " + findByAppleName);
        List<Apple> appleList = appleRepository.findByTaste("sweet");
        appleList.forEach(System.out::println);
    }
}
package com.sujan.example.jpa.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;

@Data
@Entity
@ToString
@NoArgsConstructor
@AllArgsConstructor()
@NamedQuery(name = "Apple.findByAppleName", query = "select a from Apple a where a.appleName = ?1")
@NamedQuery(name = "Apple.findByTaste", query = "select a from Apple a where a.taste = ?1")
public class Apple {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long appleId;
    private String appleName;
    private String taste;

    public Apple(String appleName, String taste) {
        this.appleName = appleName;
        this.taste = taste;
    }
}
package com.sujan.example.jpa.repository;

import com.sujan.example.jpa.entity.Apple;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface AppleRepository extends JpaRepository<Apple, Long> {
    Apple findByAppleName(String appleName);

    List<Apple> findByTaste(String taste);
}
package com.sujan.example.jpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class JpaApplication {
    public static void main(String[] args) {
        SpringApplication.run(JpaApplication.class, args);
    }
}
spring.datasource.url=jdbc:mysql://localhost:3306/AppleDb
spring.datasource.username=root
spring.datasource.password=root
plugins {
    id 'org.springframework.boot' version '2.3.3.RELEASE'
    id 'io.spring.dependency-management' version '1.0.10.RELEASE'
    id 'java'
}
group = 'com.sujan'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '11'
configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}
repositories {
    mavenCentral()
}
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    annotationProcessor 'org.projectlombok:lombok'
    compileOnly 'org.projectlombok:lombok'
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    runtimeOnly 'mysql:mysql-connector-java'
    testImplementation('org.springframework.boot:spring-boot-starter-test') {
        exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
    }
}
test {
    useJUnitPlatform()
}
curl --location --request GET 'http://localhost:8080/'
select apple0_.apple_id as apple_id1_0_, apple0_.apple_name as apple_na2_0_, apple0_.taste as taste3_0_ from apple apple0_ where apple0_.apple_name=?
findByAppleName = Apple(appleId=1, appleName=Macintosh, taste=tangy)
select apple0_.apple_id as apple_id1_0_, apple0_.apple_name as apple_na2_0_, apple0_.taste as taste3_0_ from apple apple0_ where apple0_.taste=?
Apple(appleId=2, appleName=Fuji, taste=sweet)
Apple(appleId=4, appleName=Jonagold, taste=sweet)

follow us on