web-dev-qa-db-fra.com

Avez-vous besoin d'une transaction de base de données pour lire les données?

Lorsque j'essaie de lire les données de la base de données, au moins en utilisant

((Session)em.getDelegate()).createCriteria()

une exception est levée en disant qu'une transaction n'est pas présente.

Lorsque j'ajoute l'annotation:

@Transactional(
    value = SomeClass.TRANSACTIONAL_MANAGER, 
    propagation = Propagation.SUPPORTS, 
    readOnly = true
)

ça fonctionne bien.

Cependant, comme la lecture se produira des millions de fois par seconde pour accéder aux données et les lire, je veux m'assurer que notre environnement n'est pas obstrué inutilement.

Sinon, quel est le coût de création d'une lecture seule Propagation.Supports transaction?

Puis-je ne pas créer une requête de critères d'hibernation sans transaction, en combinaison avec Spring?

25
mmm

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 des transactions (BEGIN/COMMIT/ROLLBACK).

Si vous ne déclarez pas de limites de transaction, chaque instruction devra être exécutée dans une transaction distincte (mode autocommit). Cela peut même conduire à ouvrir et fermer une connexion par instruction, sauf si votre environnement peut gérer la liaison connexion par thread.

Déclarer un service comme @Transactional vous donnera une connexion pour toute la durée de la transaction, et toutes les instructions utiliseront cette connexion d'isolement 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 réduire le 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 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 (au printemps @Transactional vous permet de marquer les transactions en lecture seule, ce qui présente un grand avantage en termes de performances).

Maintenant, si vous utilisez des limites de transaction déclaratives (par exemple @Transactional), vous devez vous assurer que l'acquisition de la connexion à la base de données est retardée jusqu'à ce qu'une instruction JDBC soit exécutée. Dans JTA, c'est le comportement par défaut. Lorsque vous utilisez RESOURCE_LOCAL, vous devez définir hibernate.connection.provider_disables_autocommit propriété de configuration et assurez-vous que le pool de connexions sous-jacent est défini pour désactiver le mode de validation automatique.

96
Vlad Mihalcea

Accompagner mon expérience avec [~ # ~] jpa [~ # ~] implémentation dans J2EE , un gestionnaire de transactions est toujours nécessaire pour effectuer [~ # ~] crud [ ~ # ~] sécurité de fonctionnement, en garantissant un retour en arrière afin de préserver l'intégrité des données.

Les applications d'entreprise utilisent différentes ressources pour enregistrer des données et envoyer des messages comme une base de données ou une file d'attente de messages. Si nous voulons interroger ces ressources séquentiellement et annuler toute l'opération une fois qu'un problème se produit, nous devons placer cette requête dans une unité de travail afin qu'elle soit exécutée dans son ensemble.

Vous pouvez le définir:

  • en utilisant des annotations connexes (comme indiqué dans les questions); de cette façon, le conteneur charge automatiquement le gestionnaire de transactions pour un contexte de persistance donné;

  • en injectant manuellement le gestionnaire de transactions, comme suit:

    public class sample {
    
        @PersistenceContext
        EntityManager em;
    
        // Injected transaction manager
        @Inject
        UserTransaction utx;
    
        private static final String[] GAME_TITLES = {
            "Super Mario Brothers",
            "Mario Kart",
            "F-Zero"
        };
    
        private void clearData() throws Exception {
            utx.begin();
            em.joinTransaction();
            System.out.println("Dumping old records...");
            em.createQuery("delete from Game").executeUpdate();
            utx.commit();
        }
    
        private void insertData() throws Exception {
            utx.begin();
            em.joinTransaction();
            System.out.println("Inserting records...");
            for (String title : GAME_TITLES) {
                Game game = new Game(title);
                em.persist(game);
            }
            utx.commit();
            // clear the persistence context (first-level cache)
            em.clear();
        }
    
        // ...
    
    }
    

Les données Spring , en tant qu'implémentation JPA, peuvent suivre la même approche.

Vous pouvez trouver plus d'informations en lisant l'article suivant: Java_Persistence/Transactions.

1
vdenotaris