web-dev-qa-db-fra.com

Spring Transaction Management fonctionne-t-il avec Spring WebFlux?

La prise en charge de Spring pour la gestion des transactions SGBDR fonctionne-t-elle également dans Spring WebFlux?

Par exemple, en supposant une configuration correcte, une méthode annotée avec @Transactional annotation utiliser le gestionnaire de transactions Spring et annuler la transaction en cas d'erreur?

Si la gestion des transactions fonctionne, un @Transactional méthode réellement throw et exception, ou le type de retour Mono ou Flux doit-il émettre un signal d'erreur?

Je sais que JDBC est intrinsèquement bloquant, et donc toutes les opérations JDBC doivent être reliées du blocage à réactif, ou vice-versa.

Le gestionnaire de transactions Spring fonctionne en utilisant un ThreadLocal (à droite?) Qui, je suppose, ne fonctionnera pas dans un environnement Reactor, car Reactor est économe en threads et un seul thread peut échanger une unité de travail pour un autre tandis que le premier attend les E/S. Je sais que Reactor a l'objet Context qui est conceptuellement similaire à ThreadLocal (à droite?) Mais je n'ai vu aucune documentation qui mentionne que la transaction l'utilise. De plus, toutes les opérations JDBC qui se produisent dans une transaction doivent utiliser le même Connection, ce qui peut être difficile à faire dans un contexte réactif.

Mon organisation a de l'expérience avec WebFlux et Cassandra, mais Cassandra possède un pilote réactif natif.

Je vous remercie!

11
user3303372

AFAIK, la gestion des transactions standard de Spring ne fonctionne pas avec WebFlux.

L'utilisation de @Transactional Ne fonctionnera pas car lorsqu'une méthode annotée est appelée, le mécanisme de transaction enregistre l'état de la transaction dans le ThreadLocal du thread appelant. Comme vous l'avez dit vous-même, cela ne fonctionne pas. Il bloque ET il partage l'état.

Cependant, vous pouvez utiliser une .runOn(Schedulers.parallel()) afin d'envoyer le code de blocage à un autre thread. De cette façon, vous pouvez avoir un pool de threads avec des threads bloquables que vous pouvez configurer pour avoir la même taille que votre pool de connexions DB.

Mais même ainsi, vous ne pouvez toujours pas compter sur @Transactional En raison de la façon dont le pool de bandes de roulement réutilise les threads. Dans une architecture de servlet standard, vous avez un thread par requête HTTP. Lorsque la réponse est renvoyée, le thread est arrêté, ce qui ferme la transaction. Dans ce cas cependant, le planificateur Reactor ne ferme pas les threads et les réutilise pour d'autres événements. Donc, même si vous POUVEZ bloquer, vous avez toujours le même problème qu'auparavant.

Vous avez l'option Context que vous avez mentionnée et je pense que cela fonctionnerait pour Mono. Je ne sais pas si cela fonctionnerait pour un Flux (je pense que tous les événements d'un flux partagent le même contexte, ce que vous ne voulez pas).

Une autre option consiste à utiliser un Touple2 avec T1 Comme objet métier et T2 Le contexte de transaction. Je ne peux cependant pas recommander cela, car vous mélangez la logique métier avec des éléments techniques et cela complique les choses.

Mon meilleur pari serait de faire vous-même la gestion des transactions/connexions:

  1. Obtenir une connexion DB
  2. Ouvrir TX
  3. Ne bloquer IO stuff
  4. Fermer TX
  5. Fermer/libérer la connexion DB

tout en un bloc de code sur un thread de blocage.

Ce sera plus sûr (pas de fuites) et plus facile à comprendre. De plus, étant donné que vous faites tout vous-même, vous pouvez choisir le type de gestion des erreurs qui convient le mieux à votre scénario.

2
Liviu Ilea