10、声明式事务
2018-10-14 本文已影响0人
小manong
一、基础回顾
1、导入相关的依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.0.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.44</version>
</dependency>
2、进行相关的配置操作
- 配置数据源
- JdbcTemplate操作数据
- @EnableTransactionManagement 开启基于注解的事务管理功能
- 配置事务管理器来控制事务
@EnableTransactionManagement
@ComponentScan("com.qiu.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());
}
}
3、给方法上标注 @Transactional 表示当前方法是一个事务方法
- UserDao
@Repository
public class UserDao {
@Autowired
private JdbcTemplate jdbcTemplate;
public void insert(){
String sql = "INSERT INTO `tbl_user`(username,age) VALUES(?,?)";
String username = UUID.randomUUID().toString().substring(0, 5);
jdbcTemplate.update(sql, username,19);
}
}
- UserService
@Service
public class UserService {
@Autowired
private UserDao userDao;
@Transactional
public void insertUser(){
userDao.insert();
//otherDao.other();xxx
System.out.println("插入完成...");
//失败则回滚否则成功插入数据库
int i = 10/0;
}
}
二、原理
- 前面知道了@EnableXXX注解主要作用是导入相应的功能类,因此从这个注解入手
1、@EnableTransactionManagement
//开始spring事物管理
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//给容器导入TransactionManagementConfigurationSelector
@Import(TransactionManagementConfigurationSelector.class)
public @interface EnableTransactionManagement {
//默认java的jdk代理方式
boolean proxyTargetClass() default false;
//默认事物以代理方式进行
AdviceMode mode() default AdviceMode.PROXY;
int order() default Ordered.LOWEST_PRECEDENCE;
}
2、TransactionManagementConfigurationSelector类
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
//默认导入AutoProxyRegistrar和ProxyTransactionManagementConfiguration两个组件
return new String[] {AutoProxyRegistrar.class.getName(), ProxyTransactionManagementConfiguration.class.getName()};
case ASPECTJ:
//如果是ASPECTJ则导入其他
return new String[] {TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
2.1AutoProxyRegistrar
public class AutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
private final Log logger = LogFactory.getLog(getClass());
//根据给定的注解注册相应的bean
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean candidateFound = false;
Set<String> annoTypes = importingClassMetadata.getAnnotationTypes();
for (String annoType : annoTypes) {
AnnotationAttributes candidate = AnnotationConfigUtils.attributesFor(importingClassMetadata, annoType);
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) {
//给容器中注册一个 InfrastructureAdvisorAutoProxyCreator 后置处理器组件
//InfrastructureAdvisorAutoProxyCreator 利用后置处理器机制在对象创建以后,包装对象,
//返回一个代理对象(增强器),代理对象执行方法利用拦截器链进行调用;
AopConfigUtils.registerAutoProxyCreatorIfNecessary(registry);
if ((Boolean) proxyTargetClass) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
return;
}
}
}
}
if (!candidateFound) {
String name = getClass().getSimpleName();
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 occured 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));
}
}
}
2.2ProxyTransactionManagementConfiguration
- 是一个配置类,主要给容器中注册事务增强器
@Configuration
public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration {
//1、事务增强器要用事务注解的信息,
@Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME)
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() {
BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor();
advisor.setTransactionAttributeSource(transactionAttributeSource());
advisor.setAdvice(transactionInterceptor());
advisor.setOrder(this.enableTx.<Integer>getNumber("order"));
return advisor;
}
//2.利用AnnotationTransactionAttributeSource解析事务注解
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionAttributeSource transactionAttributeSource() {
return new AnnotationTransactionAttributeSource();
}
//3.事务拦截器保存了事务属性信息,事务管理器等信息
@Bean
@Role(BeanDefinition.ROLE_INFRASTRUCTURE)
public TransactionInterceptor transactionInterceptor() {
TransactionInterceptor interceptor = new TransactionInterceptor();
interceptor.setTransactionAttributeSource(transactionAttributeSource());
if (this.txManager != null) {
interceptor.setTransactionManager(this.txManager);
}
return interceptor;
}
}
- 事务拦截器工作原理
1、在目标方法执行的时候,执行拦截器链,对事物进行拦截
2、先获取事务相关的属性
3、再获取PlatformTransactionManager,如果事先没有添加指定任何transactionmanger,最终会从容器中按照类型获取一个PlatformTransactionManager;
4、执行目标方法。如果异常,获取到事务管理器,利用事务管理回滚操作,如果正常,利用事务管理器,提交事务。