Quel est le "meilleur" moyen d'effectuer des transactions distribuées sur plusieurs bases de données à l'aide de Spring et d'Hibernate

StackOverflow https://stackoverflow.com/questions/128377

Question

J'ai une application, qui ressemble plus à un utilitaire, qui se trouve dans un coin et met à jour périodiquement deux bases de données différentes.

C’est une petite application autonome qui a été créée avec un contexte d’application Spring. Le contexte contient deux usines de session Hibernate configurées, qui utilisent à leur tour des sources de données DBCP communes configurées dans Spring.

Actuellement, la gestion des transactions n’existe pas, mais j’aimerais en ajouter. La mise à jour d’une base de données dépend de la réussite de la mise à jour de l’autre.

L'application ne se trouve pas dans un conteneur Java EE - elle est démarrée par une classe de programme de démarrage statique appelée à partir d'un script shell. La classe launcher instancie le contexte d'application, puis appelle une méthode sur l'un de ses beans.

Quel est le "meilleur" moyen de mettre la transactionnalité autour des mises à jour de la base de données?

Je vous laisse la définition de "meilleur", mais je pense que cela devrait être une fonction de "facile à configurer", "facile à configurer", "peu coûteuse" et "facile à empaqueter et à redistribuer". Naturellement, FOSS serait bon.

Était-ce utile?

La solution

La meilleure façon de répartir les transactions sur plusieurs bases de données est la suivante: ne pas.

Certaines personnes vous dirigeront vers XA mais XA (ou Two Phase Commit) est un mensonge (ou du marketing).

Imagine: une fois que la première phase a indiqué au gestionnaire XA qu’il peut envoyer la validation finale, la connexion réseau à l’une des bases de données échoue. Maintenant quoi? Temps libre? Cela laisserait l'autre base de données corrompue. Retour en arrière? Deux problèmes: vous ne pouvez pas annuler un commit et comment savez-vous ce qui est arrivé à la deuxième base de données? La connexion réseau a peut-être échoué une fois les données validées et uniquement le "succès". le message a été perdu?

Le meilleur moyen est de copier les données à un endroit unique. Utilisez un schéma qui vous permet d’abandonner la copie et de la poursuivre à tout moment (par exemple, ignorez les données que vous possédez déjà ou commandez l’option select by ID et demandez uniquement les enregistrements > MAX (ID) de votre copie). Protégez ceci avec une transaction. Ce n'est pas un problème puisque vous ne lisez que les données de la source. Ainsi, lorsque la transaction échoue pour une raison quelconque, vous pouvez ignorer la base de données source. Il s’agit donc d’une ancienne et simple transaction source unique.

Une fois les données copiées, traitez-les localement.

Autres conseils

Configurez un gestionnaire de transactions dans votre contexte. Les documents de printemps ont des exemples, et c'est très simple. Ensuite, lorsque vous souhaitez exécuter une transaction:

try { 
    TransactionTemplate tt = new TransactionTemplate(txManager);

    tt.execute(new TransactionCallbackWithoutResult(){
    protected void doInTransactionWithoutResult(
            TransactionStatus status) {
        updateDb1();
        updateDb2();
    }
} catch (TransactionException ex) {
    // handle 
}

Pour plus d'exemples et d'informations, regardez peut-être ceci: transactions XA à l'aide de Spring

Lorsque vous parlez de "deux bases de données différentes", voulez-vous dire différents serveurs de base de données ou deux schémas différents au sein du même serveur de base de données?

Si la version précédente est utilisée, si vous souhaitez une transaction complète, vous avez besoin de l'API de transaction XA, qui fournit une validation complète en deux phases. Mais plus important encore, vous avez également besoin d'un coordinateur / moniteur de transaction qui gère la propagation de transaction entre les différents systèmes de base de données. Cela fait partie de la spécification JavaEE, et une partie assez rare de cela. Le coordinateur TX lui-même est un logiciel complexe. Votre logiciel d’application (via Spring, si vous le souhaitez) communique avec le coordinateur.

Si, toutefois, vous voulez simplement parler de deux bases de données dans le même serveur de base de données, les transactions JDBC vanilla devraient fonctionner correctement, effectuez simplement vos opérations sur les deux bases de données au sein d'une même transaction.

Dans ce cas, vous aurez besoin d’un moniteur de transaction (serveur prenant en charge le protocole XA) et assurez-vous que vos bases de données prennent également en charge XA. La plupart (tous?) Des serveurs J2EE sont livrés avec le logiciel Transaction Monitor intégré. Si votre code ne s'exécute pas sur le serveur J2EE, il existe de nombreuses alternatives - Atomicos, Bitronix, etc.

Vous pouvez essayer Spring ChainedTransactionManager - http://docs.spring.io/spring-data/commons/docs/1.6.2.RELEASE/api/org/springframework/data/transaction/ChainedTransactionManager.html qui prend en charge la transaction distribuée de base de données. Cela pourrait être une meilleure alternative à XA

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top