AOP 기반의 선언적 트랜잭션 제어

1. Spring 트랜잭션 프로그래밍 개요

트랜잭션은 개발에 없어서는 안 될 필수 요소로 JDBC 개발 시에는 커넥션을 이용하여 트랜잭션을 제어하고, 마이바티스를 사용할 때는 SqlSession을 이용하여 트랜잭션을 제어하는데 단점은 명백하다. 데이터베이스 접근 기술을 바꾸면 트랜잭션 제어 방식이 항상 바뀌는데 Spring은 이러한 기술을 기반으로 트랜잭션을 통합적으로 제어할 수 있는 인터페이스를 제공합니다. Spring의 트랜잭션은 프로그램적 트랜잭션 제어와 선언적 트랜잭션 제어로 나뉩니다.

여기에 이미지 설명 삽입

Spring 트랜잭션 프로그래밍과 관련된 세 가지 주요 클래스가 있습니다.

여기에 이미지 설명 삽입

프로그래밍 방식의 트랜잭션 제어를 배우지는 않지만 구성을 통해 선언적 트랜잭션 제어를 수행할 때 이러한 클래스의 그림자도 볼 수 있기 때문에 프로그래밍 방식의 트랜잭션 제어에 해당하는 클래스를 이해해야 합니다.

2. 테스트 환경 구축

이체 환경을 구축하기 위해 DAO계층은 출금하는 방법과 돈을 이체하는 방법이 있고, 서비스계층은 돈을 이체하는 방법이 있고, DAO계층에서 돈을 내보내고 돈을 이체하는 방법은 준비 작업은 다음과 같습니다: ⚫
Database 계정 테이블 tb_account 준비
⚫ Dao 레이어는 incrMoney와 decrMoney의 두 가지 메서드를 포함하여 AccountMapper를 준비합니다
⚫ Service 레이어는 각각 incrMoney와 decrMoney 메서드를 호출하는 transferMoney 메서드를 준비합니다
⚫ applicationContext 파일에서 Bean 관리 구성 수행
⚫ 테스트는 정상 전송 및 비정상 전송입니다.

3. XML 기반의 선언적 트랜잭션 제어

위에서 배운 AOP 기술을 결합하면 AOP를 사용하여 서비스 방식의 트랜잭션을 향상시킬 수 있다고 상상하기 쉽습니다.
⚫ 대상 클래스: AccountServiceImpl
⚫ 포인트 컷: 서비스 비즈니스 클래스의 모든 비즈니스 메소드
⚫ 알림 클래스: Spring에서 제공하는 알림 메소드가 정의되어 있으므로 설정만 하면 됨

우리는 다음을 분석합니다:
⚫ 알림 클래스는 Spring에서 제공하고 Spring 트랜잭션의 관련 좌표를 가져와야 합니다 ⚫
대상 클래스 AccountServiceImpl 구성
⚫ Advisor 태그를 사용하여 aspect를 구성합니다.

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 패키지 아래의 advice 태그 구성에 의해 제공됩니다.

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 속성 name은 어떤 메소드가 어떤 트랜잭션의 속성 구성을 수행할 것인지를 지정하는데, 여기서 구별해야 할 점은 포인트컷 표현식에서 지정한 메소드와 여기에서 지정한 메소드의 차이인가? Pointcut 표현식은 트랜잭션 향상을 수행할 수 있는 메소드를 필터링하기 위한 것이고 트랜잭션 속성 정보의 이름은 어떤 트랜잭션 속성을 구성할 메소드를 지정하는 것입니다.

여기에 이미지 설명 삽입

메서드 이름을 구성할 때 유사 일치에 *를 사용할 수도 있습니다. 예를 들면 다음과 같습니다.

<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>

isolation 속성: 트랜잭션의 격리 수준을 지정합니다.트랜잭션 동시성에는 더티 읽기, 반복 불가능한 읽기 및 팬텀/가상 읽기의 세 가지 주요 문제가 있습니다. 동시성 문제의 발생은 트랜잭션의 격리 수준을 설정하여 보장할 수 있으며 일반적으로 사용되는 것은 READ_COMMITTED 및 REPEATABLE_READ입니다.

여기에 이미지 설명 삽입

읽기 전용 속성: 현재 읽기 전용 상태를 설정하는 것으로 질의일 경우 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"/>

전파 속성: 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의 parse 메소드는 Spring 컨테이너에 구성된 이름으로 TransactionInterceptor를 등록합니다.

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