Quelqu'un peut-il expliquer à quoi servent les paramètres d' isolation et de propagation dans l'annotation @Transactional
via un exemple du monde réel? Fondamentalement quand et pourquoi je devrais choisir de changer leurs valeurs par défaut.
Réponses
Trop de publicités?Bonne question, bien que pas une banale pour répondre.
Définit la façon dont les transactions se rapportent les uns aux autres. Options communes
-
Required
: Code s'exécutera toujours dans une transaction. Créer une nouvelle transaction ou la réutilisation d'une si disponible. -
Requires_new
: Code s'exécutera toujours dans une nouvelle transaction. Suspendre la transaction en cours si celui-ci existe.
Définit le contrat de données entre les transactions.
-
Read Uncommitted
: Permet de sale lit -
Read Committed
: Ne permet pas sale lit -
Repeatable Read
: Si une ligne est lue deux fois dans la même transaciton, le résultat sera toujours le même -
Serializable
: Effectue toutes les transactions dans une séquence
Les différents niveaux ont différentes caractéristiques de performance dans un environnement multi threaded application. Je pense que si vous comprenez l' dirty reads
concept que vous serez en mesure de sélectionner une bonne option.
Exemple, lors d'une lecture sale peut se produire
thread 1 thread 2
| |
write(x) |
| |
| read(x)
| |
rollback |
v v
value (x) is now dirty (incorrect)
Donc un sain d'esprit par défaut (si tel peut être revendiquée) pourrait être Read Comitted
, qui vous permet uniquement de lire les valeurs qui ont déjà été partie prenante par d'autres transactions en cours d'exécution, en combinaison avec un niveau d'isolement de l' Required
. Ensuite, vous pouvez travailler à partir de là si l'application a besoin des autres.
Un exemple concret où une nouvelle transaction sera toujours créé lors de la saisie de l' provideService
de routine et a terminé au moment de quitter.
public class FooService {
private Repository repo1;
private Repository repo2;
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void provideService() {
repo1.retrieveFoo();
repo2.retrieveFoo();
}
}
Si nous avions utilisé Required
, au lieu de la transaction reste ouvert si la transaction a déjà été ouverte lors de la saisie de la routine.
Notez également que le résultat d'un rollback
pourrait être différente de plusieurs exécutions de prendre part dans la même transaction.
Nous pouvons facilement vérifier le comportement d'un test et voir comment les résultats diffèrent avec la multiplication des niveaux de
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:/fooService.xml")
public class FooServiceTests {
private @Autowired TransactionManager transactionManager;
private @Autowired FooService fooService;
@Test
public void testProvideService() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
fooService.provideService();
transactionManager.rollback(status);
// assert repository values are unchanged ...
}
Avec un niveau de propagation de
Requires new
nous nous attendonsfooService.provideService()
a PAS roulé depuis il a créé son propre sous-transaction.Required
nous nous attendons à ce tout ce qui a été restaurée et magasin de sauvegarde inchangé.
PROPAGATION_REQUIRED = 0; Si DataSourceTransactionObject T1 est déjà commencé pour la Méthode M1.Si, pour une autre Méthode M2 objet de la Transaction est nécessaire ,aucune nouvelle Transaction objet est créé .Même objet T1 est utilisé pour le M2
PROPAGATION_MANDATORY = 2; la méthode doit s'exécuter dans une transaction. Si aucun transaction existante est en cours, une exception sera levée
PROPAGATION_REQUIRES_NEW = 3; Si DataSourceTransactionObject T1 est déjà commencé pour la Méthode M1 et il est en cours(d'exécution de la méthode M1) .Si une autre méthode M2 de lancer l'exécution d'alors T1 est suspendu pour la durée de la méthode M2 avec de nouveaux DataSourceTransactionObject T2 de M2.M2 exécuter à l'intérieur de son propre contexte de transaction
PROPAGATION_NOT_SUPPORTED = 4; Si DataSourceTransactionObject T1 est déjà commencé pour la Méthode M1.Si une autre méthode M2 est exécuter simultanément .Ensuite, M2 devrait pas s'exécuter à l'intérieur de contexte de transaction. T1 est suspendu jusqu'M2 est fini.
PROPAGATION_NEVER = 5; Aucune des méthodes exécuter dans le contexte de transaction.
Un niveau d'isolement: C'est au sujet de combien de transaction peut être touchées par les activités des autres concurrentes des transactions.Il l'a prend en charge la cohérence laissant les données sur plusieurs tables dans un état cohérent. Elle implique de verrouillage de lignes et/ou des tables dans une base de données.
Le problème avec les multiples de transaction
Le scénario 1.Si T1 transaction lit les données du tableau A1 qui a été écrit par une autre transaction simultanée T2.Si sur le chemin du T2 est la restauration,les données obtenues par T1 est invalide.E.g a=2 est l'origine des données .Si T1 lire un=1 qui a été écrit par T2.Si T2 de restauration a=1 sera le rollback a=2 DB.Mais,Maintenant ,T1 a a=1, mais en DB la table est modifiée pour a=2.
Scénario 2.Si T1 transaction lit les données du tableau A1.Si une autre transaction simultanée(T2) mise à jour des données sur le tableau A1.Puis les données que T1 a lire est différent de tableau A1.Parce que T2 a mis à jour les données sur le tableau A1.E.g si T1 lire un=1 et T2 à jour un=2.Puis un!=b.
Le scénario 3.Si T1 transaction lit les données du tableau A1 avec un certain nombre de lignes. Si une autre transaction simultanée(T2) insère plus de lignes sur le tableau A1.L' nombre de lignes lues par T1 est différent de lignes sur le tableau A1
Le scénario 1 est appelée Sale lit
Le scénario 2 est appelé lectures non reproductibles
Le scénario 3 est appelé Fantôme lit .
Ainsi,le niveau d'isolement est de l'étendre à laquelle le Scénario 1 Scénario 2 Scénario 3 peuvent être évités. Vous pouvez obtenus complet niveau d'isolement par la mise en œuvre de verrouillage.C'est la prévention simultanées lit et écrit pour les mêmes données se produisent.Mais il affecte les performances .Le niveau d'isolation dépend de l'application à combien d'isolement est nécessaire.
ISOLATION_READ_UNCOMMITTED :Permet de lire des modifications qui n'ont pas encore été validée.Il souffre du Scénario 1 Scénario 2 Scénario 3
ISOLATION_READ_COMMITTED:Permet de lit à partir de transactions simultanées qui ont été com- mitted.Il peut souffrir de Scénario 2 Scénario 3 . Parce que d'autres opérations peuvent être mise à jour des données.
ISOLATION_REPEATABLE_READ:Plusieurs lectures d'un même champ donneront les mêmes résultats, jusqu'à ce qu'il soit changé par lui-même.Il peut souffrir de 3 Scénario.Parce que d'autres opérations peuvent être insérer les données
ISOLATION_SERIALIZABLE: Scénario 1 Scénario 2 Scénario 3 n'arrive jamais.C'est un isolement complet.Il comporte plein de verrouillage.Il affets de performance en raison de verrouillage.
Vous pouvez tester à l'aide de
public class TransactionBehaviour {
// set is either using xml Or annotation
DataSourceTransactionManager manager=new DataSourceTransactionManager();
SimpleTransactionStatus status=new SimpleTransactionStatus();
;
public void beginTransaction()
{
DefaultTransactionDefinition Def = new DefaultTransactionDefinition();
// overwrite default PROPAGATION_REQUIRED and ISOLATION_DEFAULT
// set is either using xml Or annotation
manager.setPropagationBehavior(XX);
manager.setIsolationLevelName(XX);
status = manager.getTransaction(Def);
}
public void commitTransaction()
{
if(status.isCompleted()){
manager.commit(status);
}
}
public void rollbackTransaction()
{
if(!status.isCompleted()){
manager.rollback(status);
}
}
Main method{
beginTransaction()
M1();
If error(){
rollbackTransaction()
}
commitTransaction();
}
}
Vous pouvez déboguer et de voir le résultat avec des valeurs différentes pour l'isolement et de la propagation.
Assez d'explication sur chaque paramètre est donné par d'autres réponses; Cependant vous avez demandé un exemple réel,ici est celle qui précise le rôle des différents propagation options:
Supppose vous êtes en charge de la mise en œuvre d'un service d'inscription dans lequel un e-mail de confirmation est envoyé à l'utilisateur.Vous venez avec service de deux objets, l'un pour l' inscription de l'utilisateur et l'autre pour l'envoi d' e-mails, dont le dernier est appelé à l'intérieur de la première.Par exemple quelque chose comme ceci:
/* Sign Up service */
@Service
@Transactional(Propagation=REQUIRED)
class SignUpService{
...
void SignUp(User user){
...
SendEmail(User);
}
}
/* E-Mail Service */
@Service
@Transactional(Propagation=REQUIRES_NEW)
class EmailService{
...
void sendMail(User user){
try{
... // Trying to send the e-mail
}catch( Exception)
}
}
Vous avez peut-être remarqué que le deuxième service est de type de propagation de REQUIRES_NEW et en outre les chances sont qu'il déclenche une exceptin (serveur SMTP vers le bas ,non valides e-mail ou d'autres raisons).Vous ne voulez probablement pas l'ensemble du processus de roll-back, comme la suppression à l'utilisateur des informations à partir de la base de données ou d'autres choses; à cet effet, vous appelez la deuxième service dans une transaction distincte.
De retour à notre exemple, cette fois vous êtes préoccupé par la sécurité de base de données, de sorte que vous définissez vos classes DAO de cette façon:
/* User DAO */
@Transactional(Propagation=MANDATORY)
class UserDAO{
// some CRUD methods
}
Ce qui signifie que chaque fois qu'un objet DAO, et donc un potentiel d'accès à la db, est créé, nous devons les rassurer que l'appel a été fait à partir de l'intérieur de l'un de nos services, ce qui signifie que des transactions en direct doit exister, sinon une exception se produit.À cet effet, la propagation est de type OBLIGATOIRE.
Vous avez presque ne voulez pas utiliser Read Uncommited
car il n'est pas vraiment ACID
conforme. Read Commmited
est un bon point de départ. Repeatable Read
est probablement nécessaire uniquement dans les rapports, cumulatif ou de l'agrégation des scénarios. Notez que de nombreux DBs, postgres inclus ne fait pas de soutien Repeatable Read, vous devez utiliser Serializable
à la place. Serializable
est utile pour des choses que vous savez avoir lieu de manière totalement indépendante de toute autre chose; pensez-y comme synchronized
en Java. Serializable va de pair avec l' REQUIRES_NEW
de propagation.
J'utilise REQUIRES
pour toutes les fonctions de mise à JOUR ou SUPPRIMER des requêtes ainsi que le "service" au niveau des fonctions. Pour DAO niveau des fonctions qui fonctionnent uniquement Sélectionne, j'utilise SUPPORTS
qui va participer à un TX si l'on est déjà commencé (c'est à dire d'être appelé à partir d'une fonction de service).
L'Isolation de la Transaction et de la Transaction de Propagation bien que liés, mais sont clairement deux des concepts très différents. Dans les deux cas, les valeurs par défaut sont personnalisés au client de limite, soit en utilisant Déclarative, la gestion des transactions ou Programmatique, la gestion des transactions. Les détails de chacun des niveaux d'isolement et de la propagation des attributs peuvent être trouvés dans la référence des liens ci-dessous.
Pour deux ou plusieurs transactions en cours d'exécution/connexions à une base de données, comment et quand sont les modifications apportées par les requêtes en une seule transaction impact/visible pour les requêtes dans une autre transaction. Il est également lié à ce type de base de données de verrouillage d'enregistrement va être utilisé pour isoler les modifications apportées dans cette transaction à partir d'autres opérations et vice-versa. C'est généralement mis en œuvre par la base de données/de la ressource en participant à la transaction.
.
Dans une application d'entreprise pour toute demande/traitement il y a beaucoup de composants qui sont impliqués pour faire le travail. Certains de ces composants marquer les limites (début/fin) d'une opération qui sera utilisé dans le composant et ses sous-composants. Pour ce transactionnelle limite de composants de Transaction, la Propagation spécifie si l'élément sera ou ne sera pas participer à l'opération et ce qui se passe si le composant appelant a déjà ou ne dispose pas d'une transaction déjà créé/commencé. C'est la même que Java EE Attributs de Transaction. C'est généralement mis en œuvre par la transaction du client/gestionnaire de connexion.
Référence: