Spring Data Jpa Async query results

Some times we came accross scnerion where we need to run a long process/query in the backgroud, or dont need response from it. for these types of requirement Spring frameowk provides Asynchronous processing. The execution call will return imidiately upon invocation but the actual process / query will run in the background.

On top of Spring frameowrk Async proessing, Spring Data Jpa also provides Asysn query execution. the method call will return but the query will keep on executing in the backgrond. All the Async processing /query execution will be submitted to a Spring TaskExecutor. Asynchronous query execution is different from reactive query execution.

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 );
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;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

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

    @GetMapping("save")
    public void saveAll() {
        appleService.saveAll();
    }

    @GetMapping
    public void findByAppleName() throws ExecutionException, InterruptedException {
        Future<List<Apple>> apple = appleRepository.findByAppleName("Macintosh");
        apple.get().forEach(System.out::println);
    }
}
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.LongStream;

@Service
public class AppleService {
    @Autowired
    private AppleRepository appleRepository;

    @Async
    public void saveAll() {
        List<Apple> appleList = new ArrayList<>();
        LongStream.rangeClosed(1, 10000).forEach(i -> {
            appleList.add(new Apple("Macintosh", "sweet"));
        });
        appleRepository.saveAll(appleList);
    }
}
package com.sujan.example.jpa.entity;

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

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

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
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.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.concurrent.Future;

@Repository
public interface AppleRepository extends JpaRepository<Apple, Long> {
    @Async
    Future<List<Apple>> findByAppleName(String appleName);
}
package com.sujan.example.jpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
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/'
curl --location --request GET 'http://localhost:8080/save'
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=?

 

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 );
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;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

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

    @GetMapping("save")
    public void saveAll() {
        appleService.saveAll();
    }

    @GetMapping
    public void findByAppleName() throws ExecutionException, InterruptedException {
        CompletableFuture<List<Apple>> apple = appleRepository.findByAppleName("Macintosh");
        apple.thenAccept(System.out::println);
    }
}
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.LongStream;

@Service
public class AppleService {
    @Autowired
    private AppleRepository appleRepository;

    @Async
    public void saveAll() {
        List<Apple> appleList = new ArrayList<>();
        LongStream.rangeClosed(1, 10000).forEach(i -> {
            appleList.add(new Apple("Macintosh", "sweet"));
        });
        appleRepository.saveAll(appleList);
    }
}
package com.sujan.example.jpa.entity;

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

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

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
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.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;

import java.util.List;
import java.util.concurrent.CompletableFuture;

@Repository
public interface AppleRepository extends JpaRepository<Apple, Long> {
    @Async
    CompletableFuture<List<Apple>> findByAppleName(String appleName);
}
package com.sujan.example.jpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
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/'
curl --location --request GET 'http://localhost:8080/save'
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=?
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 );
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.util.concurrent.ListenableFuture;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;
import java.util.concurrent.ExecutionException;

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

    @GetMapping("save")
    public void saveAll() {
        appleService.saveAll();
    }

    @GetMapping
    public void findByAppleName() throws ExecutionException, InterruptedException {
        ListenableFuture<List<Apple>> apple = appleRepository.findByAppleName("Macintosh");
        apple.completable().thenAccept(System.out::println);
    }
}
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.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.LongStream;

@Service
public class AppleService {
    @Autowired
    private AppleRepository appleRepository;

    @Async
    public void saveAll() {
        List<Apple> appleList = new ArrayList<>();
        LongStream.rangeClosed(1, 10000).forEach(i -> {
            appleList.add(new Apple("Macintosh", "sweet"));
        });
        appleRepository.saveAll(appleList);
    }
}
package com.sujan.example.jpa.entity;

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

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

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
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.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;
import org.springframework.util.concurrent.ListenableFuture;

import java.util.List;

@Repository
public interface AppleRepository extends JpaRepository<Apple, Long> {
    @Async
    ListenableFuture<List<Apple>> findByAppleName(String appleName);
}
package com.sujan.example.jpa;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@SpringBootApplication
@EnableAsync
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/'
curl --location --request GET 'http://localhost:8080/save'
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=?

follow us on