web-dev-qa-db-fra.com

Spring Webflux + JPA: les référentiels réactifs ne sont pas pris en charge par JPA

Je reçois une erreur lorsque je lance mon application JPA: Reactive Repositories are not supported by JPA. Mon Pom a des dépendances et j'utilise Spring Boot 2.0.5

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>

        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <scope>runtime</scope>
        </dependency>

voici l'interface de mon référentiel.

public interface CustomerRepository extends ReactiveCrudRepository {
}

quand je lance mon application, cela génère une erreur:

org.springframework.dao.InvalidDataAccessApiUsageException: Reactive Repositories are not supported by JPA. Offending repository is com.example.demo.CustomerRepository!
    at org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport.useRepositoryConfiguration(RepositoryConfigurationExtensionSupport.Java:310) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
    at org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport.getRepositoryConfigurations(RepositoryConfigurationExtensionSupport.Java:103) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
    at org.springframework.data.repository.config.RepositoryConfigurationDelegate.registerRepositoriesIn(RepositoryConfigurationDelegate.Java:126) ~[spring-data-commons-2.0.10.RELEASE.jar:2.0.10.RELEASE]
    at org.springframework.boot.autoconfigure.data.AbstractRepositoryConfigurationSourceSupport.registerBeanDefinitions(AbstractRepositoryConfigurationSourceSupport.Java:60) ~[spring-boot-autoconfigure-2.0.5.RELEASE.jar:2.0.5.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.lambda$loadBeanDefinitionsFromRegistrars$1(ConfigurationClassBeanDefinitionReader.Java:358) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at Java.util.LinkedHashMap.forEach(LinkedHashMap.Java:684) ~[na:1.8.0_144]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsFromRegistrars(ConfigurationClassBeanDefinitionReader.Java:357) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitionsForConfigurationClass(ConfigurationClassBeanDefinitionReader.Java:145) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassBeanDefinitionReader.loadBeanDefinitions(ConfigurationClassBeanDefinitionReader.Java:117) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.Java:328) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.Java:233) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.Java:271) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.Java:91) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.Java:694) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.Java:532) ~[spring-context-5.0.9.RELEASE.jar:5.0.9.RELEASE]
    at org.springframework.boot.web.reactive.context.ReactiveWebServerApplicationContext.refresh(ReactiveWebServerApplicationContext.Java:61) ~[spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.Java:780) [spring-boot-2.0.5.RELEASE.jar:2.0.5.RELEASE]

Quelqu'un peut-il s'il vous plaît indiquer si JPA n'est pas pris en charge, que dois-je utiliser? Toute aide est la bienvenue.

12
user10400282

Si vous souhaitez bénéficier de tous les avantages de réactif, asynchrone/non bloquant, vous devez rendre toute la pile asynchrone/non bloquante. JDBC est en effet intrinsèquement une API de blocage, vous ne pouvez donc pas créer une application totalement réactive/non bloquante si vous devez accéder à la base de données via JDBC.

Mais vous avez toujours besoin d'une base de données relationnelle, puis vous recommanderez d'utiliser rxjava2-jdbc et voici un exemple complet d'utilisation de RxJava et de RxJava jdbc spring-webflux-async-jdbc-sample

Semble actuellement supporter Webflux Mongodb, Redis, etc nosql réactif donc au lieu de JPA utiliser spring-boot-starter-data-mongodb-reactive.

11
kj007

Je ne connaissais pas le support précédent, mais à compter du 09 juin 2019, vous pouvez absolument utiliser WebFlux avec les référentiels JPA!

Votre pile n'a pas besoin d'être complètement réactive. J'aime WebFlux, mais j'ai besoin d'une base de données relationnelle.

J'ai:

  • printemps-boot-starter-data-redis-reactive
  • printemps-démarrage-démarreur-webflux
  • printemps-boot-starter-data-jpa

Edit: (FYI) code est en Kotlin, mais devrait toujours fonctionner en Java.

@Configuration
@EnableTransactionManagement
@EnableJpaRepositories(basePackages = ["com.example.core.repositories"])
@EnableJpaAuditing
class PersistenceConfig

src/core/models/User

@Entity
@Table(name = "user")
class User(
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "user_id")
    var id: Long,

    @Column(name = "username")
    var username: String,

    @Column(name = "created_date", nullable = false, updatable = false)
    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    val createdDate: Date,

    @Column(name = "modified_date")
    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    val modifiedDate: Date
) : Serializable {

    /**
     * This constructor is not to be used. This is for hibernate,
     * which requires an empty constructor.
     */
    constructor() : this(1L, "", "", Date(), Date())

    companion object {
        private const val serialVersionUID = 2398467923L
    }

}

J'ai le même JPA: Reactive Repositories are not supported by JPA. erreur lorsque je retournais encore des objets mono de la requête Spring Data comme Mono<User>. Cependant, si vous supprimez le wrapper Mono, il devrait fonctionner correctement.

src/core/repositories/UserRepository

@Repository
interface UserRepository: CrudRepository<User, Long> {

    fun findUserByUsername(username: String): User?

}
2
Clement

Même si la base de données choisie (H2) ne prend pas en charge les requêtes réactives non bloquantes, vous pouvez toujours extraire les données de manière bloquante, puis les traduire en un type réactif dès que possible au profit des composants en amont.

Vous ne pouvez rien faire à propos de la nature bloquante de l’appel d’une méthode sur un référentiel JPA. Ce que vous pouvez faire, cependant, est de convertir le type non réactif en un type réactif (Flux/Mono) dès que vous le recevez, afin que vous puissiez traiter les résultats de manière réactive.

Vous pouvez également utiliser d'autres bases de données prenant en charge des modèles réactifs tels que Cassandra, MongoDB, Couchbase ou Redis.

0
Yakov Burtsev

Vous pouvez essayer ce petit wrapper réactif JPA, qui n’est pas vraiment réactif, mais qui exécute les appels JDBC sur un ThreadPool isolé.

https://github.com/IBM/reactive-components

0
Javier Sainz