129 votes

Pourquoi ai-je besoin de Transaction dans Hibernate pour les opérations en lecture seule ?

Pourquoi ai-je besoin de Transaction dans Hibernate pour les opérations en lecture seule ?

La transaction suivante met-elle un verrou sur la base de données ?

Exemple de code pour extraire de la base de données :

Transaction tx = HibernateUtil.getCurrentSession().beginTransaction(); // why begin transaction?
//readonly operation here

tx.commit() // why tx.commit? I don't want to write anything

Puis-je utiliser session.close() au lieu de tx.commit() ?

156voto

ctapobep Points 1628

Les transactions pour la lecture peuvent sembler étranges et souvent les gens ne marquent pas les méthodes pour les transactions dans ce cas. Mais JDBC créera de toute façon une transaction, c'est juste qu'elle fonctionnera dans le format autocommit=true si une option différente n'a pas été définie explicitement. Mais il y a des raisons pratiques pour marquer les transactions en lecture seule :

Impact sur les bases de données

  1. L'indicateur en lecture seule peut permettre au SGBD d'optimiser ces transactions ou celles qui s'exécutent en parallèle.
  2. Le fait d'avoir une transaction qui s'étend sur plusieurs instructions SELECT garantit une isolation correcte pour les niveaux à partir de Repeatable Read ou Snapshot (voir par exemple La lecture répétée de PostgreSQL ). Sinon, deux instructions SELECT pourraient voir une image incohérente si une autre transaction est validée en parallèle. Ceci n'est pas pertinent lorsque l'on utilise le Read Committed.

Impact sur l'ORM

  1. ORM peut provoquer des résultats imprévisibles si vous ne commencez/finissez pas les transactions de manière explicite. Par exemple, Hibernate ouvrira la transaction avant la première déclaration, mais ne la terminera pas. La connexion sera donc renvoyée au Connection Pool avec une transaction non terminée. Que se passe-t-il alors ? JDBC garde le silence, donc ceci est spécifique à l'implémentation : Les pilotes MySQL et PostgreSQL annulent cette transaction, Oracle la valide. Notez que cela peut également être configuré au niveau du Connection Pool, par exemple C3P0 vous donne une telle option, rollback par défaut.
  2. Spring définit le FlushMode=MANUAL dans le cas de transactions en lecture seule, ce qui conduit à d'autres optimisations comme l'absence de vérifications sales. Cela peut conduire à un gain de performance énorme en fonction du nombre d'objets chargés.

Impact sur l'architecture et le code propre

Il n'y a aucune garantie que votre méthode n'écrive pas dans la base de données. Si vous marquez la méthode comme @Transactional(readonly=true) c'est vous qui décidez si c'est en fait possible d'écrire dans la BD dans le cadre de cette transaction. Si votre architecture est lourde et que certains membres de l'équipe choisissent de placer une requête de modification là où on ne l'attend pas, ce drapeau vous indiquera l'endroit problématique.

66voto

Vlad Mihalcea Points 3628

Toutes les instructions de la base de données sont exécutées dans le contexte d'une transaction physique, même lorsque nous ne déclarons pas explicitement les limites de la transaction (par exemple, BEGIN, COMMIT, ROLLBACK).

Si vous ne déclarez pas explicitement les limites de transaction, chaque instruction devra être exécutée dans une transaction distincte ( autocommit ). Cela peut même conduire à l'ouverture et à la fermeture d'une connexion par instruction, à moins que votre environnement ne puisse gérer la liaison connexion-par-fil.

Déclarer un service comme @Transactional vous donnera une connexion unique pour toute la durée de la transaction, et toutes les déclarations utiliseront cette connexion d'isolation unique. C'est bien mieux que de ne pas utiliser de transactions explicites en premier lieu.

Sur les grandes applications, vous pouvez avoir de nombreuses demandes simultanées, et la réduction du taux de demande d'acquisition de connexion à la base de données améliorera certainement les performances globales de votre application.

JPA n'applique pas les transactions aux opérations de lecture. Seules les écritures finissent par lancer un TransactionRequiredException au cas où vous oublieriez de lancer un contexte transactionnel. Néanmoins, il est toujours préférable de déclarer des limites de transaction même pour les transactions en lecture seule (dans Spring @Transactional vous permet de marquer les transactions en lecture seule, ce qui présente un grand avantage en termes de performances).

20voto

Donal Fellows Points 56559

Les transactions posent en effet des verrous sur la base de données - les bons moteurs de base de données gèrent les verrous simultanés de manière judicieuse - et sont utiles en cas d'utilisation en lecture seule pour s'assurer qu'aucune transaction n'a lieu. autre La transaction ajoute des données qui rendent votre vue incohérente. Vous voulez toujours une transaction (bien qu'il soit parfois raisonnable de régler le niveau d'isolation, il est préférable de ne pas le faire pour commencer) ; si vous n'écrivez jamais dans la base de données pendant votre transaction, la validation et le retour en arrière de la transaction reviennent au même (et sont très bon marché).

Maintenant, si vous avez de la chance et que vos requêtes contre la base de données sont telles que l'ORM les mappe toujours en requêtes SQL simples, vous pouvez vous passer de explicite Mais les ORM sont des systèmes relativement complexes et il n'est pas du tout sûr de se fier à un tel comportement, à moins de faire beaucoup plus d'efforts pour vérifier ce que fait réellement l'implémentation. Il est beaucoup plus facile d'écrire les limites explicites des transactions (surtout si vous pouvez le faire avec AOP ou une technique similaire pilotée par ORM ; à partir de Java 7, try-with-resources pourrait aussi être utilisé, je suppose).

16voto

Ingo Points 21438

Peu importe que vous ne fassiez que lire ou non - la base de données doit quand même garder la trace de votre jeu de résultats, car d'autres clients de la base de données peuvent vouloir écrire des données qui modifieraient votre jeu de résultats.

J'ai vu des programmes défectueux tuer d'énormes systèmes de bases de données, parce qu'ils se contentaient de lire des données, mais ne validaient jamais, forçant le journal des transactions à grossir, parce que la base de données ne peut pas libérer les données de la transaction avant un COMMIT ou un ROLLBACK, même si le client n'a rien fait pendant des heures.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X