Maison > Java > javaDidacticiel > le corps du texte

Analyse approfondie des transactions Spring (avec exemples)

不言
Libérer: 2019-01-31 10:35:39
avant
2976 Les gens l'ont consulté

Cet article vous apporte une analyse approfondie des transactions Spring (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Je pense que tout le monde utilise beaucoup la gestion des transactions Spring, mais cela peut se limiter à une annotation @Transactional ou à la configuration d'éléments liés aux transactions dans XML. Dans tous les cas, quotidiennement peut nous suffire à utiliser. Mais en tant que programmeur, que ce soit pour un entretien ou pour mieux contrôler le code que vous écrivez, vous devriez en apprendre davantage sur les détails des transactions Spring.

Ici, je vais poser quelques questions pour voir si vous pouvez y répondre instantanément :

  • Si appels imbriqués méthodes contenant des transactions, au printemps gestion des transactions, à quel point de connaissance cela appartient-il ?

  • Le framework que nous utilisons peut être Hibernate/JPA ou Mybatis Nous savons tous que la couche inférieure nécessite un objet session/connection pour nous aider à effectuer des opérations. Pour garantir l'intégrité de la transaction, nous devons utiliser le même objet pour plusieurs groupes d'opérations de base de données, et nous savons que les objets gérés par Spring IOC sont tous des session/connectioncas uniques par défaut , pourquoi cela ne provoque-t-il pas de problèmes de sécurité des threads lorsque nous l'utilisons ? Que fait exactement Spring en interne ?

  • Quel est le BPP que les gens appellent ?

  • Quelles sont les interfaces importantes pour la gestion des transactions Spring ?

1. Connaissances de base requises pour lire cet article

Mes camarades de classe qui ont lu cet article

par défaut tout le monde le connaît Printemps Avoir une certaine compréhension des connaissances liées aux affaires. (ps : si vous ne connaissez pas l'article spécifique, lisez-le et revenez ici)

Nous savons tous que les transactions Spring sont l'une des meilleures pratiques de Spring AOP, parlons donc des connaissances de base de L'AOP (simple Configuration, utilisation) doit d'abord être connu. Si vous souhaitez comprendre l'AOP de manière plus complète, vous pouvez lire cet article : Points de connaissance importants de l'AOP (introduction à la terminologie, utilisation complète). Lorsque nous parlons d’AOP, nous devons parler du principe sous-jacent de l’AOP : le modèle de conception de proxy dynamique. À ce stade, vous avez déjà une compréhension de base de l’AOP. Nous pouvons donc utiliser XML/annotations pour configurer la gestion des transactions Spring.

Dans l'apprentissage IOC, ce que l'on peut connaître c'est le cycle de vie des Beans in Spring (menant aux objets BPP) et les objets gérés par IOC sont des singletons par défaut : singleton design pattern, s'il existe un objet singleton"

State" (avec des variables membres), un si grand nombre de threads accédant à cet objet singleton peut entraîner une insécurité des threads. Alors, qu’est-ce que la sécurité des threads ? , il existe de nombreuses façons de résoudre la sécurité des threads, mais l'une d'entre elles est : laissez chaque thread avoir sa propre variable : ThreadLocal

Si vous ne savez pas grand-chose sur les points de connaissances que j'ai mentionnés ci-dessus, il est recommandé de cliquer sur le bouton bleu Entrez et apprenez quelques mots.

2. Deux exemples d'intuition peu fiable

2.1 Le premier exemple

Un ami m'a déjà posé des questions sur un exemple :

Une exception est levée au niveau de la couche Service et capturée au niveau de la couche Contrôleur. S'il y a une exception dans le service, la transaction sera-t-elle annulée ?

// Service方法
    
@Transactional
public Employee addEmployee() throws Exception {

    Employee employee = new Employee("3y", 23);
    employeeRepository.save(employee);
    // 假设这里出了Exception
    int i = 1 / 0;

    return employee;
}

// Controller调用
@RequestMapping("/add")
public Employee addEmployee() {
    Employee employee = null;
    try {
        employee = employeeService.addEmployee();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return employee;

}
Copier après la connexion
Ma

première réaction : Il ne sera pas annulé.

  • C'est ce que je pensais à l'époque : parce que la couche Service a levé une exception et qu'elle a été interceptée par le contrôleur. La restauration ou non doit être déterminée par la logique du bloc de code catch du contrôleur. Si le bloc de code catch ne revient pas en arrière, il ne doit pas revenir en arrière.

Mais après avoir testé, mon ami a dit qu'il pouvait être annulé. (pappapa gifle)

Analyse approfondie des transactions Spring (avec exemples)

Après avoir regardé le document, il s'avère que le document contient des instructions :

Par défaut, exceptions cochées n'entraîne pas que l'intercepteur transactionnel marque la transaction pour l'annulation et les instances de RuntimeException et ses sous-classes do

Conclusion : s'il s'agit d'une exception au moment de la compilation, elle ne sera pas automatiquement annulée. >S'il s'agit d'une exception d'exécution, elle sera automatiquement annulée

 ! 2.2 Le deuxième exemple

Le deuxième exemple est issu de l'article Zhihu@LiuShu, l'URL correspondante sera donnée en fin d'article

Comme vous le savez, les méthodes entourées d'annotations
peuvent être gérées par les transactions Spring. Si j'utilise une méthode sans transaction sous la classe actuelle

pour appeler une méthode avec une transaction @Transactional, alors ce que nous avons. Que se passe-t-il avec cet appel ? Y aura-t-il des affaires ? Décrivez-le en code :

Mon premier instinct est le suivant : ceci est lié au mécanisme de propagation des transactions Spring.
// 没有事务的方法去调用有事务的方法
public Employee addEmployee2Controller() throws Exception {

    return this.addEmployee();
}

@Transactional
public Employee addEmployee() throws Exception {

    employeeRepository.deleteAll();
    Employee employee = new Employee("3y", 23);

    // 模拟异常
    int i = 1 / 0;

    return employee;
}
Copier après la connexion

En fait, cela n'a rien à voir avec le mécanisme de propagation des transactions Spring

Laissez-moi le décrire ci-dessous :

    La gestion des transactions Spring utilise AOP, et la couche inférieure du proxy dynamique AOP est utilisée. Donc si on marque l'annotation
  • sur une classe ou une méthode, un

    objet proxy @Transactional sera généré.

  • Laissez-moi vous l'expliquer en images :

Analyse approfondie des transactions Spring (avec exemples)

显然地,我们拿到的是代理(Proxy)对象,调用addEmployee2Controller()方法,而addEmployee2Controller()方法的逻辑是target.addEmployee(),调用回原始对象(target)的addEmployee()。所以这次的调用压根就没有事务存在,更谈不上说Spring事务传播机制了。

Analyse approfondie des transactions Spring (avec exemples):

Analyse approfondie des transactions Spring (avec exemples)

测试结果:压根就Analyse approfondie des transactions Spring (avec exemples)

Analyse approfondie des transactions Spring (avec exemples)

2.2.1再延伸一下

从上面的测试我们可以发现:如果是在本类中没有事务的方法来调用标注注解@Transactional方法,最后的结论是没有事务的。那如果我将这个标注注解的方法移到别的Service对象上,有没有事务?

@Service
public class TestService {

    @Autowired
    private EmployeeRepository employeeRepository;
    
    @Transactional
    public Employee addEmployee() throws Exception {

        employeeRepository.deleteAll();

        Employee employee = new Employee("3y", 23);

        // 模拟异常
        int i = 1 / 0;

        return employee;
    }

}


@Service
public class EmployeeService {

    @Autowired
    private TestService testService;
    // 没有事务的方法去调用别的类有事务的方法
    public Employee addEmployee2Controller() throws Exception {
        return testService.addEmployee();
    }
}
Copier après la connexion

测试结果:

Analyse approfondie des transactions Spring (avec exemples)

因为我们用的是代理对象(Proxy)去调用addEmployee()方法,那就当然有事务了。

看完这两个例子,有没有觉得3y的直觉是真的水

三、Spring事务传播机制

如果嵌套调用含有事务的方法,在Spring事务管理中,这属于哪个知识点?

在当前含有事务方法内部调用其他的方法(无论该方法是否含有事务),这就属于Spring事务传播机制的知识点范畴了。

Spring事务基于Spring AOP,Spring AOP底层用的动态代理,动态代理有两种方式:

  • 基于接口代理(JDK代理)

    • 基于接口代理,凡是类的方法非public修饰,或者用了static关键字修饰,那这些方法都不能被Spring AOP增强

  • 基于CGLib代理(子类代理)

    • 基于子类代理,凡是类的方法使用了private、static、final修饰,那这些方法都不能被Spring AOP增强

至于为啥以上的情况不能增强,用你们的脑瓜子想一下就知道了。

值得说明的是:那些不能被Spring AOP增强的方法并不是不能在事务环境下工作了。只要它们被外层的事务方法调用了,由于Spring事务管理的传播级别,内部方法也可以工作在外部方法所启动的事务上下文中

至于Spring事务传播机制的几个级别,我在这里就不贴出来了。这里只是再次解释“啥情况才是属于Spring事务传播机制的范畴”。

四、多线程问题

我们使用的框架可能是Hibernate/JPA或者是Mybatis,都知道的底层是需要一个session/connection对象来帮我们执行操作的。要保证事务的完整性,我们需要多组数据库操作要使用同一个session/connection对象,而我们又知道Spring IOC所管理的对象默认都是单例的,这为啥我们在使用的时候不会引发线程安全问题呢?内部Spring到底干了什么?

回想一下当年我们学Mybaits的时候,是怎么编写Session工具类?

Analyse approfondie des transactions Spring (avec exemples)

没错,用的就是ThreadLocal,同样地,Spring也是用的ThreadLocal。

以下内容来源《精通 Spring4.x》

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态的“状态性对象”采用ThreadLocal封装,让它们也成为线程安全的“状态性对象”,因此,有状态的Bean就能够以singleton的方式在多线程中工作。

我们可以试着点一下进去TransactionSynchronizationManager中看一下:

Analyse approfondie des transactions Spring (avec exemples)

5. Qu'est-ce que le BPP ?

Le nom complet de BBP est : BeanPostProcessor, communément appelé Post-processeur d'objet

  • Pour faire simple, nos objets peuvent être traités via BeanPostProcessor "Traitement".

La gestion du Spring Bean (ou cycle de vie du Bean) est aussi un point de connaissance qui est souvent testé, et je vais ré- l'organiser lors du recrutement d'automne Voici les étapes, car elles sont plus importantes, je les posterai donc ici :

  1. ResouceLoader charge les informations de configuration

  2. BeanDefintionReader analyse les informations de configuration et génère une par une BeanDefintion

  3. BeanDefintion est géré par BeanDefintionRegistry

  4. BeanFactoryPostProcessor traite les informations de configuration (c'est-à-dire , traitant les informations de configuration, généralement via PropertyPlaceholderConfigurer Pour implémenter)

  5. Instancier Bean

  6. Si le Bean配置/实现instantiationAwareBean, appelez la méthode correspondante

  7. Utilisez BeanWarpper pour terminer la configuration des attributs (dépendances) entre les objets

  8. Si l'interface Bean配置/实现了Aware, appelez la méthode correspondante

  9. Si le Bean est configuré avec la méthode before de BeanPostProcessor, alors appelez

  10. Si le Bean est configuré avec init-method ou implémentez InstantiationBean, puis appelez la méthode correspondante

  11. Si le Bean est configuré avec la méthode after de BeanPostProcessor, appelez

  12. pour mettre l'objet dans le HashMap

  13. Enfin, si la méthode destroy ou DisposableBean est configurée, l'opération de destruction est effectuée

Analyse approfondie des transactions Spring (avec exemples)

Il y a aussi des images à propos du BPP :

Analyse approfondie des transactions Spring (avec exemples)

5.1 Pourquoi parler spécifiquement du BPP ?

La couche inférieure de la programmation Spring AOP utilise la technologie de proxy dynamique, et l'objet proxy doit être utilisé lors de l'appel. Alors, comment le printemps fait-il ?

J'ai seulement besoin d'écrire un BPP. Dans la méthode postProcessBeforeInitialization ou postProcessAfterInitialization, je juge l'objet pour voir s'il doit tisser dans la logique des aspects. Si c'est le cas, je générerai un BPP basé sur. cet objet. Objet proxy, puis renvoie cet objet proxy, alors ce qui est finalement injecté dans le conteneur est naturellement l'objet proxy.

Spring fournit BeanPostProcessor, qui nous permet de "traiter " les objets qui en ont besoin !

6. Comprendre plusieurs interfaces importantes des transactions Spring

Les transactions Spring peuvent être divisées en deux types :

  • Transactions programmatiques (via le code) À mettre en œuvre transactions)

  • Transactions déclaratives (pour implémenter des transactions via la configuration)

Les transactions programmatiques sont relativement simples à implémenter dans Spring car les transactions déclaratives encapsulent un. beaucoup de choses (en général on les utilise simplement, mais tout à l'intérieur est très complexe), il est beaucoup plus difficile de mettre en œuvre des transactions déclaratives.

Il existe les interfaces importantes suivantes dans les transactions programmatiques :

  • TransactionDefinition : définit les attributs de transaction compatibles avec Spring (tels que le niveau d'isolement de la transaction, la transaction propagation, délai d'expiration de la transaction, statut de lecture seule)

  • TransactionStatus : représente le état d'exécution spécifique de la transaction (obtient des informations sur l'état d'exécution de la transaction, vous pouvez également l'utiliser interface avec indirectement transactions de restauration et autres opérations)

  • PlatformTransactionManager : interface du gestionnaire de transactions (définit un ensemble de comportements et l'implémentation spécifique est confiée à différents frameworks de persistance pour compléter ---AnalogieJDBC)

Analyse approfondie des transactions Spring (avec exemples)

Dans les transactions déclaratives, en plus des interfaces TransactionStatus et PlatformTransactionManager, il existe Plusieurs interfaces importantes :

  • TransactionProxyFactoryBean : Générer un objet proxy

  • TransactionInterceptor : Implémenter l'interception d'objet

  • TransactionAttrubute : données de configuration de la transaction

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:cnblogs.com
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal
À propos de nous Clause de non-responsabilité Sitemap
Site Web PHP chinois:Formation PHP en ligne sur le bien-être public,Aidez les apprenants PHP à grandir rapidement!