Spring註解系列二十六:聲明式事務

一、基本使用
1、配置類 TxConfig 。主要有兩點:
(1)、@EnableTransactionManagement 開啓基於註解的事務管理功能;相當於<tx:annotation-driven/>
(2)、要配置事務管理器來控制事務;PlatformTransactionManager

@EnableTransactionManagement  //開啓基於註解的事務管理功能
@ComponentScan("com.atguigu.tx")
@Configuration
public class TxConfig {
	
	//數據源
	@Bean
	public DataSource dataSource() throws Exception{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser("root");
		dataSource.setPassword("123456");
		dataSource.setDriverClass("com.mysql.jdbc.Driver");
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
		return dataSource;
	}
	
	@Bean
	public JdbcTemplate jdbcTemplate() throws Exception{
		//Spring對@Configuration類會特殊處理;給容器中加組件的方法,多次調用都只是從容器中找組件
		JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource());
		return jdbcTemplate;
	}
	
	//註冊事務管理器來控制事務
	@Bean
	public PlatformTransactionManager transactionManager() throws Exception{
		return new DataSourceTransactionManager(dataSource());
	}
	
}

2、UserDao

@Repository
public class UserDao {
	
	@Autowired
	private JdbcTemplate jdbcTemplate;
	public void insert(){
		String sql = "INSERT INTO `user`(name) VALUES(?)";
		String name = UUID.randomUUID().toString().substring(0, 5);
		jdbcTemplate.update(sql, name);	
	}

}

3、@Transactional 註解表示當前方法是一個事務方法

@Service
public class UserService {
	
	@Autowired
	private UserDao userDao;
	
	@Transactional  //表示當前方法是一個事務方法
	public void insertUser(){
		userDao.insert();

		System.out.println("插入完成...");
		int i = 10/0;
	}

}

測試:

@Test
public void test01(){
	AnnotationConfigApplicationContext applicationContext = 
			new AnnotationConfigApplicationContext(TxConfig.class);

	UserService userService = applicationContext.getBean(UserService.class);
	
	userService.insertUser();
	applicationContext.close();
}

在這裏插入圖片描述
添加事務後,拋異常就會回滾操作,數據表沒有插入數據。
在這裏插入圖片描述
二、源碼解析
1、@EnableTransactionManagement
 利用TransactionManagementConfigurationSelector給容器中會導入兩個組件:AutoProxyRegistrar和ProxyTransactionManagementConfiguration;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({TransactionManagementConfigurationSelector.class})
public @interface EnableTransactionManagement {
    boolean proxyTargetClass() default false;

    AdviceMode mode() default AdviceMode.PROXY;

    int order() default 2147483647;
}
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
    public TransactionManagementConfigurationSelector() {
    }

    protected String[] selectImports(AdviceMode adviceMode) {
        switch(adviceMode) {
        case PROXY:
            return new String[]{AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
        case ASPECTJ:
            return new String[]{"org.springframework.transaction.aspectj.AspectJTransactionManagementConfiguration"};
        default:
            return null;
        }
    }
}

2、AutoProxyRegistrar
 給容器中註冊一個 InfrastructureAdvisorAutoProxyCreator 組件:利用後置處理器機制在對象創建以後,包裝對象,返回一個代理對象(增強器),代理對象執行方法利用攔截器鏈進行調用;

public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
 	boolean candidateFound = false;
    Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
    Iterator var5 = annoTypes.iterator();

    while(var5.hasNext()) {
        String annoType = (String)var5.next();
        AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
        if (candidate != null) {
            Object mode = candidate.get("mode");
            Object proxyTargetClass = candidate.get("proxyTargetClass");
            if (mode != null && proxyTargetClass != null && AdviceMode.class == mode.getClass() && Boolean.class == proxyTargetClass.getClass()) {
                candidateFound = true;
                if (mode == AdviceMode.PROXY) {
                    AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
                    if ((Boolean)proxyTargetClass) {
                        AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
                        return;
                    }
                }
            }
        }
    }

    if (!candidateFound) {
        String name = this.getClass().getSimpleName();
        this.logger.warn(String.format("%s was imported but no annotations were found having both 'mode' and 'proxyTargetClass' attributes of type AdviceMode and boolean respectively. This means that auto proxy creator registration and configuration may not have occurred as intended, and components may not be proxied as expected. Check to ensure that %s has been @Import'ed on the same class where these annotations are declared; otherwise remove the import of %s altogether.", name, name, name));
    }

}

3、ProxyTransactionManagementConfiguration的作用:給容器中註冊事務增強器;
 1)、事務增強器要用事務註解的信息,AnnotationTransactionAttributeSource解析事務註解;
 2)、事務攔截器:TransactionInterceptor;保存了事務屬性信息,事務管理器;他是一個 MethodInterceptor;在目標方法執行的時候:執行攔截器鏈;事務攔截器:
  (1)、先獲取事務相關的屬性
  (2)、再獲取PlatformTransactionManager,如果事先沒有添加指定任何transactionmanger
最終會從容器中按照類型獲取一個PlatformTransactionManager;
  (3)、執行目標方法
    如果異常,獲取到事務管理器,利用事務管理回滾操作;
    如果正常,利用事務管理器,提交事務;

@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
    public ProxyTransactionManagementConfiguration() {
    }

    @Bean(
        name = {"org.springframework.transaction.config.internalTransactionAdvisor"}
    )
    @Role(2)
    public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
        BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
        advisor.setTransactionAttributeSource(this.transactionAttributeSource());
        advisor.setAdvice(this.transactionInterceptor());
        advisor.setOrder((Integer)this.enableTx.getNumber("order"));
        return advisor;
    }

    @Bean
    @Role(2)
    public TransactionAttributeSource transactionAttributeSource() {
        return new AnnotationTransactionAttributeSource();
    }

    @Bean
    @Role(2)
    public TransactionInterceptor transactionInterceptor() {
        TransactionInterceptor interceptor = new TransactionInterceptor();
        interceptor.setTransactionAttributeSource(this.transactionAttributeSource());
        if (this.txManager != null) {
            interceptor.setTransactionManager(this.txManager);
        }

        return interceptor;
    }
}
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
    public TransactionInterceptor() {
    }

    public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
        this.setTransactionManager(ptm);
        this.setTransactionAttributes(attributes);
    }

    public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
        this.setTransactionManager(ptm);
        this.setTransactionAttributeSource(tas);
    }

    public Object invoke(final MethodInvocation invocation) throws Throwable {
        Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
        return this.invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() {
            public Object proceedWithInvocation() throws Throwable {
                return invocation.proceed();
            }
        });
    }

    private void writeObject(ObjectOutputStream oos) throws IOException {
        oos.defaultWriteObject();
        oos.writeObject(this.getTransactionManagerBeanName());
        oos.writeObject(this.getTransactionManager());
        oos.writeObject(this.getTransactionAttributeSource());
        oos.writeObject(this.getBeanFactory());
    }

    private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        this.setTransactionManagerBeanName((String)ois.readObject());
        this.setTransactionManager((PlatformTransactionManager)ois.readObject());
        this.setTransactionAttributeSource((TransactionAttributeSource)ois.readObject());
        this.setBeanFactory((BeanFactory)ois.readObject());
    }
}

TransactionAspectSupport

protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final TransactionAspectSupport.InvocationCallback invocation) throws Throwable {
    final TransactionAttribute txAttr = this.getTransactionAttributeSource().getTransactionAttribute(method, targetClass);
    final PlatformTransactionManager tm = this.determineTransactionManager(txAttr);
    final String joinpointIdentification = this.methodIdentification(method, targetClass, txAttr);
    if (txAttr != null && tm instanceof CallbackPreferringPlatformTransactionManager) {
        try {
            Object result = ((CallbackPreferringPlatformTransactionManager)tm).execute(txAttr, new TransactionCallback<Object>() {
                public Object doInTransaction(TransactionStatus status) {
                    TransactionAspectSupport.TransactionInfo txInfo = TransactionAspectSupport.this.prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);

                    TransactionAspectSupport.ThrowableHolder var4;
                    try {
                        Object var3 = invocation.proceedWithInvocation();
                        return var3;
                    } catch (Throwable var8) {
                        if (txAttr.rollbackOn(var8)) {
                            if (var8 instanceof RuntimeException) {
                                throw (RuntimeException)var8;
                            }

                            throw new TransactionAspectSupport.ThrowableHolderException(var8);
                        }

                        var4 = new TransactionAspectSupport.ThrowableHolder(var8);
                    } finally {
                        TransactionAspectSupport.this.cleanupTransactionInfo(txInfo);
                    }

                    return var4;
                }
            });
            if (result instanceof TransactionAspectSupport.ThrowableHolder) {
                throw ((TransactionAspectSupport.ThrowableHolder)result).getThrowable();
            } else {
                return result;
            }
        } catch (TransactionAspectSupport.ThrowableHolderException var14) {
            throw var14.getCause();
        }
    } else {
        TransactionAspectSupport.TransactionInfo txInfo = this.createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
        Object retVal = null;

        try {
            retVal = invocation.proceedWithInvocation();
        } catch (Throwable var15) {
            this.completeTransactionAfterThrowing(txInfo, var15);
            throw var15;
        } finally {
            this.cleanupTransactionInfo(txInfo);
        }

        this.commitTransactionAfterReturning(txInfo);
        return retVal;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章