美文网首页
10、声明式事务

10、声明式事务

作者: 小manong | 来源:发表于2018-10-14 17:11 被阅读0次

    一、基础回顾

    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、执行目标方法。如果异常,获取到事务管理器,利用事务管理回滚操作,如果正常,利用事务管理器,提交事务。

    相关文章

      网友评论

          本文标题:10、声明式事务

          本文链接:https://www.haomeiwen.com/subject/apxtzftx.html