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

107

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

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

Exemple de code à extraire de DB:

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 à la session.close() place de tx.commit()?

user93796
la source
9
La transaction est requise par le DB lui-même. Vous pouvez en savoir plus sur le mode autocommit ici: community.jboss.org/wiki/…
Bhesh Gurung
@BheshGurung, je suppose que nous n'avons besoin de la conversion que pour l'opération d'écriture
user93796
4
Avez-vous lu la partie "Démystifier les mythes de l'auto-commit" dans le lien?
Bhesh Gurung

Réponses:

131

Vous pourriez en fait avoir des raisons de marquer les transactions en lecture seule.

  1. Les transactions à lire peuvent sembler étranges et souvent les gens ne marquent pas les méthodes de transaction dans ce cas. Mais JDBC créera de toute façon une transaction, c'est juste qu'elle fonctionnera autocommit=truesi une option différente n'a pas été définie explicitement.
  2. Mais il n'y a aucune garantie que votre méthode n'écrit pas dans la base de données. Si vous marquez la méthode comme @Transactional(readonly=true), Spring définira la transaction JDBC en mode lecture seule, ainsi vous dicterez s'il est réellement possible d'écrire dans la base de données dans le cadre de cette transaction. Si votre architecture est encombrante et que certains membres de l'équipe peuvent choisir de placer la requête de modification là où elle n'est pas attendue, cet indicateur vous indiquerait l'endroit problématique.
  3. Les transactions en lecture seule peuvent également être optimisées par les DB, mais cela est bien sûr spécifique à la DB. Par exemple, MySQL a ajouté un support pour cela uniquement dans InnoDB à partir de la version 5.6.4.
  4. Si vous n'utilisez pas directement JDBC, mais plutôt un ORM, cela peut poser problème. Par exemple, la communauté Hibernate dit que travailler en dehors de la transaction peut entraîner un comportement imprévisible. En effet, Hibernate ouvrira la transaction, mais ne la fermera pas d'elle-même, ainsi la connexion sera renvoyée au pool de connexions sans que la transaction ne soit validée. Que se passe-t-il alors? JDBC garde le silence, c'est donc spécifique à l'implémentation (MySQL annule la transaction, Oracle Afair la valide). Cela peut également être configuré au niveau du pool de connexions (par exemple, C3P0 vous offre une telle option, restauration par défaut).
  5. Une autre chose en ce qui concerne Hibernate, Spring définit le FlushMode sur MANUAL en cas de transactions en lecture seule, ce qui conduit à d'autres optimisations comme pas besoin de vérifications sales.
  6. Vous souhaiterez peut-être remplacer ou définir explicitement le niveau d'isolement des transactions. Cela a également un impact sur les transactions de lecture puisque vous faites ou ne voulez pas lire les modifications non validées, être exposé à des lectures fantômes, etc.

Pour résumer, vous pouvez aller dans les deux sens, mais vous devez comprendre les conséquences.

Stanislav Bashkyrtsev
la source
Merci de votre réponse.J'utilise la mise en veille prolongée (hibernation native, pas jpa) .Mais la mise en veille prolongée me force à démarrer une transcription avant de faire une opération de base de données.Si je n'en démarre pas une, cela génère une erreur disant aucune tracscation active.Puis-je marquer la transcation comme lecture seule , si oui comment?
user93796
L'indicateur readonly est en fait défini pour la connexion, pas pour la transaction elle-même, et vous ne pouvez pas y accéder via Hibernate comme ça. Vous devez utiliser la prise en charge de Spring Transaction et utiliser des annotations ou une configuration transactionnelle basée sur XML. En faisant cela, Spring prend la propriété de la gestion des connexions et des transactions au lieu d'Hibernate.
Stanislav Bashkyrtsev
1
Très bien expliqué! Un autre article de Mark Richards explique assez bien les pièges de l'indicateur en lecture seule dans l'annotation transactionnelle - ibm.com/developerworks/java/library/j-ts1/index.html .
Mahesh
48

Toutes les instructions de 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 transaction (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 ( autocommitmode). Cela peut même conduire à l'ouverture et à la fermeture d'une connexion par instruction, sauf si votre environnement peut gérer la liaison connexion par thread.

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

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

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

Vlad Mihalcea
la source
1
"... alors chaque instruction devra être exécutée dans une transaction séparée". Le conteneur ne fait pas automatiquement le traitement par lots ?
Arash
Le traitement par lots concerne les modifications et non la lecture des données. Et même ainsi, le traitement par lots JDBC n'est pas activé par défaut lors de l'utilisation de JPA et Hibernate.
Vlad Mihalcea
1
Merci Vlad. J'ai lu certains de vos articles. Ils sont vraiment utiles.
Arash
Ce stackoverflow.com/q/34797480/179850 semble contredire un peu votre affirmation selon laquelle les transactions en lecture seule ont un grand avantage en termes de performances. Au moins, cela ne semble pas être le cas dans le contexte de la mise en veille prolongée.
nimai
Non, ce n'est pas le cas. Il s'agit de définir la lecture seule, tandis que le mien consiste à éviter la validation automatique.
Vlad Mihalcea
18

Les transactions placent 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 avec une utilisation en lecture seule pour s'assurer qu'aucune autre transaction n'ajoute de données qui rendent votre vue incohérente. Vous voulez toujours une transaction (bien qu'il soit parfois raisonnable d'ajuster le niveau d'isolement, il vaut mieux ne pas le faire pour commencer); si vous n'écrivez jamais dans la base de données pendant votre transaction, la validation et l'annulation de la transaction s'avèrent être les mêmes (et 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 sur des requêtes SQL uniques, vous pouvez vous en sortir sans transactions explicites , en vous appuyant sur le comportement d'autocommit intégré de la base de données, mais les ORM sont des systèmes relativement complexes il n'est donc pas du tout sûr de s'appuyer sur un tel comportement à moins que vous ne travailliez beaucoup plus à vérifier ce que fait réellement l'implémentation. Il est beaucoup plus facile d'écrire les limites de transaction explicites (surtout si vous pouvez le faire avec AOP ou une technique similaire basée sur l'ORM; à partir de Java 7, try-with-resources pourrait être utilisé aussi je suppose).

Boursiers Donal
la source
14

Peu importe que vous lisiez uniquement ou non - la base de données doit toujours garder une trace de votre jeu de résultats, car d'autres clients de base de données peuvent vouloir écrire des données qui modifieraient votre jeu de résultats.

J'ai vu des programmes défectueux pour tuer d'énormes systèmes de base de données, car ils lisent simplement des données, mais ne s'engagent jamais, forçant le journal des transactions à croître, car la base de données ne peut pas libérer les données de transaction avant un COMMIT ou un ROLLBACK, même si le client n'a rien fait Pendant des heures.

Ingo
la source