web-dev-qa-db-fra.com

Transaction printanière REQUIRED vs REQUIRES_NEW: transaction d'annulation

J'ai une méthode qui a le propagation = Propagation.REQUIRES_NEW propriété transactionnelle:

@Transactional(propagation = Propagation.REQUIRES_NEW)
public void createUser(final UserBean userBean) {
    //Some logic here that requires modification in DB
}

Cette méthode peut être appelée plusieurs fois simultanément et pour chaque transaction, si une erreur survient, elle est annulée (indépendamment des autres transactions).

Le problème est que cela peut forcer Spring à créer plusieurs transactions, même si une autre est disponible, et peut entraîner des problèmes de performances.


Java doc de propagation = Propagation.REQUIRED dit: Support a current transaction, create a new one if none exists.

Cela semble résoudre le problème de performance, n'est-ce pas?

Qu'en est-il du problème de restauration? Que se passe-t-il si un nouvel appel de méthode est annulé lors de l'utilisation d'une transaction existante? cela ne va-t-il pas annuler toute la transaction, même les appels précédents?

[EDIT] Je suppose que ma question n'était pas assez claire:

Nous avons des centaines de clients connectés à notre serveur.

Pour chaque client, nous devons naturellement envoyer un retour d’information sur la transaction (OK ou exception -> annulation).

Ma question est la suivante: si j'utilise REQUIRED, cela signifie-t-il qu'une seule transaction est utilisée et que si le centième client rencontre un problème, la transaction du premier client sera également annulée?

46
Majid Laissi

En utilisant REQUIRES_NEW n'est pertinent que lorsque la méthode est appelée à partir d'un contexte transactionnel; Lorsque la méthode est appelée à partir d'un contexte non transactionnel, elle se comportera exactement comme REQUIRED - elle créera une nouvelle transaction.

Cela ne signifie pas qu'il n'y aura qu'une seule transaction pour tous vos clients - chaque client partira d'un contexte non transactionnel, et dès que le traitement de la demande atteindra un @Transactional, cela créera une nouvelle transaction.

Donc, dans cet esprit, si vous utilisez REQUIRES_NEW est logique pour la sémantique de cette opération - que je ne m'inquiéterais pas de la performance - cela ferait de l'optimisation prématurée des manuels scolaires - je mettrais plutôt l'accent sur l'exactitude et l'intégrité des données et sur la performance une fois les métriques de performance collectées, et pas avant.

Sur la restauration - en utilisant REQUIRES_NEW forcera le début d'une nouvelle transaction. Une exception annulera cette transaction. S'il existe également une autre transaction qui s'exécutait également - elle sera annulée ou non selon que l'exception remonte dans la pile ou est interceptée - votre choix, en fonction des spécificités des opérations. De plus, pour une discussion plus approfondie sur les stratégies transactionnelles et leur retour en arrière, je recommanderais: "Stratégies transactionnelles: comprendre les pièges des transactions", Mark Richards .

69
Eugen

Si vous avez vraiment besoin de le faire dans une transaction séparée, vous devez utiliser REQUIRES_NEW et vivre avec la surcharge de la performance. Attention aux cadenas.

Je préférerais le faire dans l'autre sens:

  • Validez les données du côté Java.
  • Exécutez tout en une seule transaction.
  • Si quelque chose ne va pas du côté de la base de données -> c'est une erreur majeure de la conception de la base de données ou de la validation. Annulez tout et jetez une erreur critique de premier niveau.
  • Écrivez de bons tests unitaires.
11
Piotr Gwiazda