AOPベースの宣言型トランザクション制御

1. Springトランザクションプログラミングの概要

開発においてトランザクションは欠かせないものですが、JDBC開発ではconnectionを使ってトランザクションを制御しますが、MyBatisを使う場合はSqlSessionを使ってトランザクションを制御しますが、デメリットは明らかです。データベースアクセス技術が切り替わると、トランザクション制御の方法も必ず変わりますが、Spring ではこれらの技術をベースにトランザクションを一元的に制御するためのインターフェースを提供します。Spring のトランザクションは、プログラムによるトランザクション制御と宣言的なトランザクション制御に分かれています。

ここに画像の説明を挿入

Spring トランザクション プログラミングに関連する主なクラスは 3 つあります。

ここに画像の説明を挿入

プログラムによるトランザクション制御については学習しませんが、構成を通じて宣言型トランザクション制御を実行するときに、これらのクラスの影も見えるため、プログラムによるトランザクション制御に対応するクラスを理解する必要があります。

2. テスト環境を構築する

送金環境を構築するには、dao層に送金メソッド、送金メソッド、サービス層に送金メソッドがあり、dao層の送金メソッドと送金メソッドは準備作業は次のとおりです: ⚫
データベース アカウント テーブル tb_account を準備します;
⚫ Dao 層は、incrMoney と decrMoney の 2 つのメソッドを含む AccountMapper を準備します;
⚫ サービス層は、それぞれ incrMoney メソッドと decrMoney メソッドを呼び出す transferMoney メソッドを準備します;
⚫ applicationContext ファイルで Bean 管理の設定を実行します;
⚫ テストは正常な転送と異常な転送です。

3. XMLベースの宣言型トランザクション制御

上記で学んだ AOP テクノロジを組み合わせると、AOP を使用して Service メソッドのトランザクションを強化できることは容易に想像できます。
⚫対象クラス:AccountServiceImpl
⚫ポイントカット:サービスビジネスクラス内の全ビジネスメソッド
⚫通知クラス:Springより提供、通知メソッドは定義済み、設定のみ

分析します:
⚫ 通知クラスは Spring によって提供され、Spring トランザクションの関連する座標をインポートする必要があります;
⚫ ターゲット クラス AccountServiceImpl を設定します;
⚫ アスペクトを設定するためにアドバイザー タグを使用します。

Spring トランザクションの関連する座標をインポートします。spring-jdbc 座標には spring-tx 座標が導入されました。

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-jdbc</artifactId>
	<version>5.2.13.RELEASE</version>
</dependency>

ここに画像の説明を挿入

ターゲット クラス AccountServiceImpl を構成する

<bean id="accountService" class="com.itheima.service.impl.AccoutServiceImpl">
	<property name="accountMapper" ref="accountMapper"></property>
</bean>

Advisor タグを使用してアスペクトを構成する

<aop:config>
	<aop:advisor advice-ref="Spring提供的通知类" pointcut="execution(* com.itheima.service.impl.*.*(..))"/>
</aop:config>

質問: Spring が提供する通知クラスは誰ですか? これは、spring-tx パッケージのアドバイス タグ設定によって提供されます。

xmlns:tx="http://www.springframework.org/schema/tx" 
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/springtx.xsd

<!--Spring提供的事务通知-->
<tx:advice id="myAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<tx:method name="transferMoney"/>
	</tx:attributes>
</tx:advice>

<!--平台事务管理器-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>

<aop:config>
	<aop:advisor advice-ref="myAdvice" pointcut="execution(* com.itheima.service.impl.*.*(..))"/>
</aop:config>

上記の構成を詳しく説明します。

まず、プラットフォーム トランザクション マネージャー PlatformTransactionManager は、トランザクションの特定の操作をカプセル化するために Spring によって提供される標準インターフェイスであり、トランザクションのコミット メソッドとロールバック メソッドをカプセル化します。

public interface PlatformTransactionManager extends TransactionManager {
    
    
	TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
	void commit(TransactionStatus var1) throws TransactionException;
	void rollback(TransactionStatus var1) throws TransactionException;
}

異なる永続層フレームワークは異なる方法で動作する可能性があるため、異なる永続層フレームワークには異なるプラットフォーム トランザクション マネージャー実装が含まれる場合があります。
たとえば、MyBatis が永続層フレームワークとして使用される場合、使用されるプラットフォーム トランザクション マネージャー実装は DataSourceTransactionManager です。
Hibernate が永続層フレームワークとして使用される場合、使用されるプラットフォーム トランザクション マネージャーは HibernateTransactionManager です。

次に、トランザクション定義情報の構成です。各トランザクションには、分離レベル、読み取り専用ステータス、タイムアウト時間などの多くの特性があります。これらの情報は、開発時に接続を通じて指定でき、ここでは構成ファイルを通じて構成されます。

<tx:attributes>
	<tx:method name="方法名称"
			isolation="隔离级别"
			propagation="传播行为"
			read-only="只读状态"
			timeout="超时时间"/>
</tx:attributes>

このうち name 属性名は、どのトランザクションのどのメソッドで属性設定を行うかを指定するものですが、ここで区別する必要があるのは、ポイントカット式で指定するメソッドとここで指定するメソッドの違いでしょうか。ポイントカット式は、どのメソッドがトランザクション拡張を実行できるかをフィルタリングするものであり、トランザクション属性情報の名前は、どのメソッドでどのトランザクション属性を設定するかを指定するものです。

ここに画像の説明を挿入

メソッド名を構成するときは、次のように、あいまい一致に * を使用することもできます。

<tx:advice id="myAdvice" transaction-manager="transactionManager">
	<tx:attributes>
		<!--精确匹配transferMoney方法-->
		<tx:method name="transferMoney"/>
		<!--模糊匹配以Service结尾的方法-->
		<tx:method name="*Service"/>
		<!--模糊匹配以insert开头的方法-->
		<tx:method name="insert*"/>
		<!--模糊匹配以update开头的方法-->
		<tx:method name="update*"/>
		<!--模糊匹配任意方法,一般放到最后作为保底匹配-->
		<tx:method name="*"/>
	</tx:attributes>
</tx:advice>

分離属性: トランザクションの分離レベルを指定します。トランザクションの同時実行には、ダーティ リード、非反復読み取り、ファントム/仮想読み取りという 3 つの大きな問題があります。同時実行性の問題の発生は、トランザクションの分離レベルを設定することで保証できます。一般的に使用されるのは READ_COMMITTED と REPEATABLE_READ です。

ここに画像の説明を挿入

read-only 属性: 現在の読み取り専用ステータスを設定します。クエリの場合は true に設定すると、クエリのパフォーマンスが向上します。更新 (追加、削除、変更) 操作の場合は、false に設定します。

<!-- 一般查询相关的业务操作都会设置为只读模式 -->
<tx:method name="select*" read-only="true"/>
<tx:method name="find*" read-only="true"/>

timeout 属性: トランザクション実行のタイムアウト時間を秒単位で設定します。制限時間を超えてもトランザクションが完了していない場合、トランザクションは自動的にロールバックされ、実行は継続されません。デフォルト値は -1 で、タイムアウト制限はありません。

<!-- 设置查询操作的超时时间是3秒 -->
<tx:method name="select*" read-only="true" timeout="3"/>

propagation 属性: 主に A メソッドが B メソッドを呼び出すときのトランザクションの伝播方法の問題を解決するために、トランザクションの伝播動作を設定します。たとえば、一方的なトランザクションを使用する、または A と B の両方が独自のトランザクションを使用するなどです。トランザクションの伝播動作には、次の 7 つのプロパティ値を設定できます。

ここに画像の説明を挿入
ここに画像の説明を挿入

XML モードでの宣言型トランザクション制御の原理を分析してみましょう。
<tx:advice> タグで使用される名前空間プロセッサは TxNamespaceHandler で、内部的に登録されているパーサーは
TxAdviceBeanDefinitionParserです。

this.registerBeanDefinitionParser("advice", new TxAdviceBeanDefinitionParser());

登録するBeanDefinitionはTxAdviceBeanDefinitionParserで指定します

protected Class<?> getBeanClass(Element element) {
    
    
	return TransactionInterceptor.class;
}

TxAdviceBeanDefinitionParser の 2 番目の親クラス AbstractBeanDefinitionParser の解析メソッドは、設定された名前で TransactionInterceptor を Spring コンテナに登録します。

parserContext.registerComponent(componentDefinition);

TransactionInterceptor の invoke メソッドが実行され、invoke メソッドを追跡し、最後にトランザクションの開始と送信が表示されます
⚫ トランザクションは AbstractPlatformTransactionManager の 132 行目で開かれ、
トランザクションは TransactionAspectSupport の 242 行目でコミットされます。

4. アノテーションベースの宣言型トランザクション制御

注釈は XML の代替手段です

@Service("accountService")
public class AccoutServiceImpl implements AccountService {
    
    
	@Autowired
	private AccountMapper accountMapper;
	
	// <tx:method name="*" isolation="REPEATABLE_READ" propagation="REQUIRED“/>
	@Transactional(isolation = Isolation.REPEATABLE_READ,propagation = Propagation.REQUIRED,readOnly = false,timeout = 5)
	public void transferMoney(String decrAccountName, String incrAccountName, int money) {
    
    
		accountMapper.decrMoney(decrAccountName,money); //转出钱
		int i = 1/0; //模拟某些逻辑产生的异常
		accountMapper.incrMoney(incrAccountName,money); //转入钱
	}
}

同様に、プラットフォーム トランザクション マネージャーは、使用されるトランザクション アノテーションに合わせて設定する必要があり、トランザクション アノテーション スイッチをオンにする必要があります。

<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>

<!--配置事务的注解驱动-->
<tx:annotation-driven transaction-manager="transactionManager"/>

完全なアノテーションを使用する場合は、構成ファイルの代わりに次の構成クラスを使用します。

@Configuration
@ComponentScan("com.itheima.service")
@PropertySource("classpath:jdbc.properties")
@MapperScan("com.itheima.mapper")
@EnableTransactionManagement
public class ApplicationContextConfig {
    
    
@Bean
public PlatformTransactionManager tansactionManager(DataSource dataSource){
    
    
	DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
	transactionManager.setDataSource(dataSource);
	return transactionManager;
}
	// ... 省略其他配置 ...
}

おすすめ

転載: blog.csdn.net/qq_36602071/article/details/129953523