복붙노트

[SPRING] 웹 스프링스 봄과 데이터베이스에서 읽기

SPRING

웹 스프링스 봄과 데이터베이스에서 읽기

Spring 5에서는 webflux를 사용하여 나머지 API에 반응 형 프로그래밍 스타일을 도입했습니다. 나는 그 자체로 상당히 새롭고 Flux 나 Mono 로의 데이터베이스에 대한 동기 호출을 우선적 인 의미로 만드는 것을 궁금해했다. 그렇다면 다음과 같이하십시오.

@RestController
public class HomeController {

    private MeasurementRepository repository;

    public HomeController(MeasurementRepository repository){
        this.repository = repository;
    }

    @GetMapping(value = "/v1/measurements")
    public Flux<Measurement> getMeasurements() {
        return Flux.fromIterable(repository.findByFromDateGreaterThanEqual(new Date(1486980000L)));
    }

}

비동기 CrudRepository와 같은 것이 있습니까? 나는 그것을 발견 할 수 없었다.

해결법

  1. ==============================

    1.한 가지 옵션은 완전히 비 차단 인 대체 SQL 클라이언트를 사용하는 것입니다. 몇 가지 예는 다음과 같습니다. https://github.com/mauricio/postgresql-async 또는 https://github.com/finagle/roc. 물론 이들 드라이버 중 어느 것도 공식적으로 데이터베이스 공급 업체에서 지원하지 않습니다. 또한, 기능은 Hibernate 나 jOOQ와 같은 성숙한 JDBC 기반 추상화와 비교할 때 훨씬 덜 매력적입니다.

    한 가지 옵션은 완전히 비 차단 인 대체 SQL 클라이언트를 사용하는 것입니다. 몇 가지 예는 다음과 같습니다. https://github.com/mauricio/postgresql-async 또는 https://github.com/finagle/roc. 물론 이들 드라이버 중 어느 것도 공식적으로 데이터베이스 공급 업체에서 지원하지 않습니다. 또한, 기능은 Hibernate 나 jOOQ와 같은 성숙한 JDBC 기반 추상화와 비교할 때 훨씬 덜 매력적입니다.

    대안적인 아이디어는 스칼라 세계에서 나에게 찾아왔다. 블로킹 호출을 격리 된 ThreadPool에 보내어 블로킹 및 비 블로킹 호출을 함께 섞어서는 안됩니다. 이를 통해 우리는 전반적인 스레드 수를 제어 할 수 있으며 잠재적 인 최적화를 통해 CPU가 기본 실행 컨텍스트에서 비 차단 작업을 처리 할 수 ​​있습니다. Spring 데이터 JPA와 같이 실제로 블로킹하는 JDBC 기반의 구현이 있다고 가정하면, 비동기로 실행하고 전용 스레드 풀로 디스패치 할 수 있습니다.

    @RestController
    public class HomeController {
    
        private final MeasurementRepository repository;
        private final Scheduler scheduler;
    
        public HomeController(MeasurementRepository repository, @Qualifier("jdbcScheduler") Scheduler scheduler) {
            this.repository = repository;
            this.scheduler = scheduler;
        }
    
        @GetMapping(value = "/v1/measurements")
        public Flux<Measurement> getMeasurements() {
            return Mono.fromCallable(() -> repository.findByFromDateGreaterThanEqual(new Date(1486980000L))).publishOn(scheduler);
        }
    
    }
    

    JDBC 용 스케줄러는 연결 수와 동일한 크기의 전용 스레드 풀을 사용하여 구성해야합니다.

    @Configuration
    public class SchedulerConfiguration {
        private final Integer connectionPoolSize;
    
        public SchedulerConfiguration(@Value("${spring.datasource.maximum-pool-size}") Integer connectionPoolSize) {
            this.connectionPoolSize = connectionPoolSize;
        }
    
        @Bean
        public Scheduler jdbcScheduler() {
            return Schedulers.fromExecutor(Executors.newFixedThreadPool(connectionPoolSize));
        }
    
    }
    

    그러나이 접근법에는 어려움이 있습니다. 주요한 것은 트랜잭션 관리입니다. JDBC에서 트랜잭션은 단일 java.sql.Connection 내에서만 가능합니다. 한 트랜잭션에서 여러 작업을 수행하려면 연결을 공유해야합니다. 우리가 그들 사이에 어떤 계산을하고 싶다면, 우리는 연결을 유지해야합니다. 그 사이에 계산을 수행하는 동안 제한된 수의 연결이 유휴 상태로 유지되므로 이는 그리 효과적이지 않습니다.

    비동기 JDBC 래퍼에 대한 아이디어는 새로운 것이 아니며 스칼라 라이브러리 인 Slick 3에서 이미 구현되었습니다. 마지막으로 비 블로킹 JDBC가 Java 로드맵에 올 수 있습니다. 2016 년 9 월 JavaOne에서 발표되었으므로 Java 10에서 볼 수 있습니다.

  2. ==============================

    2.Spring 데이터는 Mongodb 및 Cassandra의 반응 저장소 인터페이스를 지원합니다.

    Spring 데이터는 Mongodb 및 Cassandra의 반응 저장소 인터페이스를 지원합니다.

    Spring 데이터 MongoDb 반응 인터페이스

    Spring 데이터 MongoDB는 Project Reactor 및 RxJava 1 반응 형을 사용하여 반응 적 저장소 지원을 제공합니다. 반응 API는 반응 형간에 반응 형 변환을 지원합니다.

    public interface ReactivePersonRepository extends ReactiveCrudRepository<Person, String> {
    
        Flux<Person> findByLastname(String lastname);
    
        @Query("{ 'firstname': ?0, 'lastname': ?1}")
        Mono<Person> findByFirstnameAndLastname(String firstname, String lastname);
    
        // Accept parameter inside a reactive type for deferred execution
        Flux<Person> findByLastname(Mono<String> lastname);
    
        Mono<Person> findByFirstnameAndLastname(Mono<String> firstname, String lastname);
    
        @InfiniteStream // Use a tailable cursor
        Flux<Person> findWithTailableCursorBy();
    
    }
    
    public interface RxJava1PersonRepository extends RxJava1CrudRepository<Person, String> {
    
        Observable<Person> findByLastname(String lastname);
    
        @Query("{ 'firstname': ?0, 'lastname': ?1}")
        Single<Person> findByFirstnameAndLastname(String firstname, String lastname);
    
        // Accept parameter inside a reactive type for deferred execution
        Observable<Person> findByLastname(Single<String> lastname);
    
        Single<Person> findByFirstnameAndLastname(Single<String> firstname, String lastname);
    
        @InfiniteStream // Use a tailable cursor
        Observable<Person> findWithTailableCursorBy();
    }
    
  3. ==============================

    3.플럭스 또는 모노를 얻는 것이 반드시 전용 스레드에서 실행된다는 것을 의미하지는 않습니다. 대신 대부분의 운영자는 이전 운영자가 실행 한 스레드에서 계속 작업합니다. 지정하지 않는 한 최상위 연산자 (소스) 자체는 subscribe () 호출이 이루어진 스레드에서 실행됩니다.

    플럭스 또는 모노를 얻는 것이 반드시 전용 스레드에서 실행된다는 것을 의미하지는 않습니다. 대신 대부분의 운영자는 이전 운영자가 실행 한 스레드에서 계속 작업합니다. 지정하지 않는 한 최상위 연산자 (소스) 자체는 subscribe () 호출이 이루어진 스레드에서 실행됩니다.

    지속성 API (JPA, JDBC) 또는 네트워킹 API를 사용할 수 없게하는 경우 Spring MVC는 최소한 공통 아키텍처에 가장 적합한 선택입니다. Reactor와 RxJava 모두 별도의 스레드에서 블로킹 호출을 수행하는 것이 기술적으로 가능하지만 논 블로킹 웹 스택을 최대한 활용하지는 않습니다.

    그래서 ... 동기식 차단 전화를 어떻게 포장합니까?

    Callable을 사용하여 실행을 지연합니다. 그리고 Schedulers.elastic을 사용해야합니다. 다른 리소스를 묶지 않고 블로킹 리소스를 기다리는 전용 스레드를 생성하기 때문입니다.

    예:

    Mono.fromCallable(() -> blockingRepository.save())
            .subscribeOn(Schedulers.elastic());
    
  4. ==============================

    4.이 블로그를 기반으로 다음과 같이 스 니펫을 다시 작성해야합니다.

    이 블로그를 기반으로 다음과 같이 스 니펫을 다시 작성해야합니다.

    @GetMapping(value = "/v1/measurements")
    public Flux<Measurement> getMeasurements() {
        return Flux.defer(() -> Flux.fromIterable(repository.findByFromDateGreaterThanEqual(new Date(1486980000L))))
               .subscribeOn(Schedulers.elastic());
    }
    
  5. from https://stackoverflow.com/questions/42299455/spring-webflux-and-reading-from-database by cc-by-sa and MIT license