Oh, c'est aujourd'hui la veille de Noël ~: Santa :: flocon de neige:
Ne vous inquiétez pas pour cela ... Cette fois, je vais vous montrer comment contrôler les transactions sur Spring Boot sans utiliser @ Transactional
(gestion des transactions par annotation).
Certaines personnes peuvent penser que vous devriez utiliser @ Transactional
, mais comme vous ne pouvez spécifier @ Transaction
que pour les composants que vous créez, la bibliothèque OSS créée par le tiers ne dépend pas de Spring. Il n'est pas possible d'appliquer une transaction à une méthode telle que (évidemment ...: sweat_smile :).
En plus de la méthode d'utilisation des annotations pour spécifier la méthode à échanger au printemps,
Les méthodes, etc. sont prises en charge.
Si vous utilisez Spring depuis longtemps, vous avez peut-être vu la déclaration de contrôle de transaction suivante dans la définition de Bean à l'aide de XML. Dans cet exemple, toutes les méthodes publiques de la classe TxDemoApplication
sont soumises au contrôle des transactions.
src/resources/transactionContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
">
<tx:advice id="transactionAdvisor">
<tx:attributes>
<tx:method name="*" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="txDemoApplicationPointcut" expression="execution(* com.example.TxDemoApplication.*(..))"/>
<aop:advisor advice-ref="transactionAdvisor" pointcut-ref="txDemoApplicationPointcut"/>
</aop:config>
</beans>
Même sur Spring Boot, si vous créez un fichier XML comme ↑ et le chargez en utilisant @ ImportResource
comme indiqué ci-dessous, cela fonctionnera.
@SpringBootApplication
@ImportResource("classpath:/transactionContext.xml")
public class TxDemoApplication implements CommandLineRunner {
// ...
}
Mais ... je ne veux plus revenir au fichier XML ...: sweat_smile:, Si vous utilisez Spring from Spring Boot (ceux qui ne connaissent que Java Config), je me demande comment définir les beans en utilisant XML ~ Par conséquent, il y a des gens: wink:
Si vous voulez exprimer la même chose en utilisant Java Config ... Créez simplement la configuration Java suivante.
@Configuration
public class TransactionConfig {
@Bean
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
PlatformTransactionManager transactionManager) {
//Spécifiez la méthode de gestion des transactions et les valeurs d'attribut requises pour le contrôle des transactions.
MethodMapTransactionAttributeSource source = new MethodMapTransactionAttributeSource();
source.addTransactionalMethod(TxDemoApplication.class, "*", new RuleBasedTransactionAttribute());
//Générer un conseiller AOP qui contrôle les transactions
//Conseils pour le contrôle des transactions(TransactionInteceptor)Le point de coupe qui spécifie l'emplacement d'application de est lié à la méthode spécifiée dans ↑.
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(source);
advisor.setAdvice(new TransactionInterceptor(transactionManager, source));
return advisor;
}
}
Note:
Si vous voulez utiliser ce mécanisme, vous avez besoin du JAR de ʻorg.aspectj: aspectjweaver
dans le chemin de classe, alors ajoutez ʻorg.springframework.boot: spring-boot-starter-aop
comme bibliothèque dépendante. ..<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
Warning:
Avec Spring Boot, le mécanisme de configuration automatique permet également un mécanisme de contrôle des transactions en utilisant
@ Transactional
(gestion des transactions par annotations). Par conséquent ... Si@ Transactional
est ajouté à la méthode spécifiée dans Java Config dans ↑, Advice (TransactionInteceptor
) pour le contrôle des transactions sera appliqué deux fois, donc soyez prudent.
Dans l'exemple ci-dessus, MethodMapTransactionAttributeSource
est utilisé, mais Spring fournit des classes d'implémentation pour TransactionAttributeSource
.
nom de la classe | La description |
---|---|
NameMatchTransactionAttributeSource |
Appliquer le contrôle des transactions aux méthodes qui correspondent au nom de méthode spécifié (modèle) |
MethodMapTransactionAttributeSource |
Appliquer le contrôle de transaction au nom de méthode spécifié (modèle) de la classe spécifiée |
MatchAlwaysTransactionAttributeSource |
Appliquer le contrôle des transactions à toutes les méthodes |
AnnotationTransactionAttributeSource |
Appliquer le contrôle des transactions aux méthodes de classe annotées Spring, JTA et EJB (cette classe est utilisée avec la configuration automatique de Spring Boot) |
CompositeTransactionAttributeSource |
plurielTransactionAttributeSource Agréger et appliquer le contrôle des transactions |
BeanFactoryTransactionAttributeSourceAdvisor
vous donne la possibilité de filtrer les classes auxquelles s'applique l'AOP. Par exemple ... Si vous souhaitez appliquer uniquement les beans auxquels @ Service
est affecté, vous pouvez définir les beans suivants.
@Configuration
public class TransactionConfig {
@Bean
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
PlatformTransactionManager transactionManager) {
NameMatchTransactionAttributeSource source = new NameMatchTransactionAttributeSource();
source.addTransactionalMethod("*", new RuleBasedTransactionAttribute());
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(source);
advisor.setAdvice(new TransactionInterceptor(transactionManager, source));
advisor.setClassFilter(clazz -> AnnotationUtils.findAnnotation(clazz, Service.class) != null); //Mettre en œuvre les conditions de filtrage et`setClassFilter`Appel
return advisor;
}
}
Vous trouverez ci-dessous un exemple d'application créé pour la vérification des opérations.
Téléchargez le projet en sélectionnant "JDBC", "H2" et "AOP" comme bibliothèques dépendantes sur "SPRING INITIALIZR".
Définissez le mode de sortie du journal Spring JDBC sur débogage pour voir si la transaction a été appliquée.
src/resources/application.properties
logging.level.org.springframework.jdbc=debug
Ensuite, implémentez CommandRunner
dans l'application Spring Boot et définissez le bean pour le contrôle des transactions.
package com.example;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.interceptor.BeanFactoryTransactionAttributeSourceAdvisor;
import org.springframework.transaction.interceptor.MethodMapTransactionAttributeSource;
import org.springframework.transaction.interceptor.RuleBasedTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionInterceptor;
@SpringBootApplication
public class TxDemoApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(TxDemoApplication.class, args);
}
private final JdbcOperations jdbcOperations;
public TxDemoApplication(JdbcOperations jdbcOperations) {
this.jdbcOperations = jdbcOperations;
}
@Override //Cette méthode est soumise au contrôle des transactions, mais ...@Transactionnel n'est pas accordé! !!
public void run(String... args) throws Exception {
Integer value = jdbcOperations.queryForObject("SELECT 1", Integer.class);
System.out.println(value);
}
@Configuration
static class TransactionConfig {
@Bean
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor(
PlatformTransactionManager transactionManager) {
MethodMapTransactionAttributeSource source = new MethodMapTransactionAttributeSource();
source.addTransactionalMethod(TxDemoApplication.class, "*", new RuleBasedTransactionAttribute());
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(source);
advisor.setAdvice(new TransactionInterceptor(transactionManager, source));
return advisor;
}
}
}
Maintenant, exécutons l'application Spring Boot.
$ ./mvnw spring-boot:run
...
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v1.4.3.RELEASE)
2016-12-24 16:20:30.713 INFO 58327 --- [ main] com.example.TxDemoApplication : Starting TxDemoApplication on Kazuki-no-MacBook-Pro.local with PID 58327 (/Users/shimizukazuki/Downloads/tx-demo/target/classes started by shimizukazuki in /Users/shimizukazuki/Downloads/tx-demo)
2016-12-24 16:20:30.715 INFO 58327 --- [ main] com.example.TxDemoApplication : No active profile set, falling back to default profiles: default
2016-12-24 16:20:30.748 INFO 58327 --- [ main] s.c.a.AnnotationConfigApplicationContext : Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@1e2e2b3: startup date [Sat Dec 24 16:20:30 JST 2016]; root of context hierarchy
2016-12-24 16:20:31.454 INFO 58327 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2016-12-24 16:20:31.469 DEBUG 58327 --- [ main] o.s.j.d.DataSourceTransactionManager : Creating new transaction with name [com.example.TxDemoApplication$$EnhancerBySpringCGLIB$$9f83f17d.run]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT
2016-12-24 16:20:31.609 DEBUG 58327 --- [ main] o.s.j.d.DataSourceTransactionManager : Acquired Connection [ProxyConnection[PooledConnection[conn9: url=jdbc:h2:mem:testdb user=SA]]] for JDBC transaction
2016-12-24 16:20:31.611 DEBUG 58327 --- [ main] o.s.j.d.DataSourceTransactionManager : Switching JDBC Connection [ProxyConnection[PooledConnection[conn9: url=jdbc:h2:mem:testdb user=SA]]] to manual commit
2016-12-24 16:20:31.618 DEBUG 58327 --- [ main] o.s.jdbc.core.JdbcTemplate : Executing SQL query [SELECT 1]
1
2016-12-24 16:20:31.638 DEBUG 58327 --- [ main] o.s.j.d.DataSourceTransactionManager : Initiating transaction commit
2016-12-24 16:20:31.638 DEBUG 58327 --- [ main] o.s.j.d.DataSourceTransactionManager : Committing JDBC transaction on Connection [ProxyConnection[PooledConnection[conn9: url=jdbc:h2:mem:testdb user=SA]]]
2016-12-24 16:20:31.639 DEBUG 58327 --- [ main] o.s.j.d.DataSourceTransactionManager : Releasing JDBC Connection [ProxyConnection[PooledConnection[conn9: url=jdbc:h2:mem:testdb user=SA]]] after transaction
2016-12-24 16:20:31.639 DEBUG 58327 --- [ main] o.s.jdbc.datasource.DataSourceUtils : Returning JDBC Connection to DataSource
2016-12-24 16:20:31.642 INFO 58327 --- [ main] com.example.TxDemoApplication : Started TxDemoApplication in 1.106 seconds (JVM running for 3.466)
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.612 s
[INFO] Finished at: 2016-12-24T16:20:31+09:00
[INFO] Final Memory: 24M/315M
[INFO] ------------------------------------------------------------------------
2016-12-24 16:20:31.742 INFO 58327 --- [ Thread-1] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext@1e2e2b3: startup date [Sat Dec 24 16:20:30 JST 2016]; root of context hierarchy
2016-12-24 16:20:31.744 INFO 58327 --- [ Thread-1] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
Si vous regardez le journal de la console, vous pouvez voir que la transaction est démarrée, validée et terminée avant et après l'implémentation de SQL: clap :: clap :: clap:
Il peut ne pas être utilisé souvent, mais ... Vous pouvez contrôler les transactions pour les méthodes qui n'ont pas @ Transactional
.
En gros, je pense qu'il vaut mieux ajouter @ Transactional
pour contrôler les transactions des composants que vous créez vous-même, mais selon les exigences de l'application, la méthode introduite cette fois peut être efficace dans certains cas. Hmm.
Happy Christmas 2016 !! :wave:
Recommended Posts