13_Spring事务

文章目录

  • Spring事务
    • 使用Spring框架对Mybatis整合
    • 事务的核心接口
      • PlatformTransactionManager平台事务管理器
      • TransactionStatus事务状态
      • TransactionDefinition事务定义
      • 事务的传播行为
      • TransactionTemplate
      • Transactional注解

Spring事务

使用Spring框架对Mybatis整合

在这里插入图片描述
上图中:绿色是手动注册的组件,黄色的是MapperScannerConfigure注册的组件

  1. 引入依赖
 <!--Spring整合Mybatis依赖-->
 <dependency>
     <groupId>org.mybatis</groupId>
     <artifactId>mybatis-spring</artifactId>
     <version>2.0.7</version>
 </dependency>
 <dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-jdbc</artifactId>
     <version>5.2.15.RELEASE</version>
 </dependency>

<!--druid依赖-->
<!--可以监控程序的运行-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.11</version>
</dependency>
  1. 组件注册
@Configuration
@ComponentScan("com.coo1heisenberg.demo2")
public class AppConfiguration {
//    @Bean
//    public SqlSessionFactory sqlSessionFactory() {
//
//        try {
//            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
//                    .build(Resources.getResourceAsStream("mybatis.xml"));
//            return sqlSessionFactory;
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return null;
//    }

    /**
     * mybatis-spring这个依赖提供了一个类,能够注册sqlSessionFactory组件
     *
     * sqlSessionFactoryBean implements FactoryBean<sqlSessionFactory>
     */
    @Bean
    public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource) {
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        return sqlSessionFactoryBean;
    }

    @Bean
    public DataSource dataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/coo1heisenberg?useSSL=false&characterEncoding=utf8");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }

    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer() {
        MapperScannerConfigurer configurer = new MapperScannerConfigurer();
        // 使用set方法提供一些信息
        // 就会根据这些信息向mapper中注册组件
        configurer.setSqlSessionFactoryBeanName("sqlSessionFactory");
        // sqlSessionFactory = applicationContext.getBean(beanName);

        configurer.setBasePackage("com.coo1heisenberg.demo2.mapper");

        return configurer;
    }
}
  1. 在Service中可以直接注册Mapper
@Service
public class AccountServiceImpl implements AccountService {

//    @Autowired
//    SqlSessionFactory sqlSessionFactory;

    @Autowired
    AccountMapper accountMapper;
    @Override
    public int transfer(Integer fromId, Integer destId, Double money) {
//        SqlSession sqlSession = sqlSessionFactory.openSession(true);
//        AccountMapper mapper = sqlSession.getMapper(AccountMapper.class);

        Double fromMoney = accountMapper.selectByPrimaryKey(fromId) - money;
        Double destMoney = accountMapper.selectByPrimaryKey(destId) + money;

        accountMapper.upDate(fromId, fromMoney);
        int i = 1
        accountMapper.upDate(destId, destMoney);

        return 0;
    }
}
  1. 测试文件
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = AppConfiguration.class)
public class MybatisSpringTest {
    @Autowired
    AccountService accountService;

    @Test
    public void test() {
        accountService.transfer(1, 2, 100.0);
    }
}

总结:Spring在Mybatis执行mapper的方法之后会立刻提交事务,而有时需要将多个方法放到一个事务里


事务的核心接口

  • PlatformTransactionManager 平台事务管理器
  • TransactionStatus 事务状态
  • TransactionDefinition 事务定义

PlatformTransactionManager平台事务管理器

  • 平台事务管理器,Spring要管理事务,必须使用事务管理器
  • 有多种实现,通过实现此接口,Spring可以管理任何实现了这些接口的事务
  • 常见的事务管理器的实现:
    • DataSourceTransactionManagerjdbc开发时事务管理器,使用JdbcTemplateMyBatis(SSM)
    • HibernateTransactionManagerHibernate开发时事务管理器,整合Hibernate(SSH)
public interface PlatformTransactionManager extends TransactionManager {
  // 开启事务
    TransactionStatus getTransaction(@Nullable TransactionDefinition var1) 
    throws TransactionException;
  
  // 提交事务
    void commit(TransactionStatus var1) throws TransactionException;
  
  // 回滚事务
    void rollback(TransactionStatus var1) throws TransactionException;
}

TransactionStatus事务状态

  • 获取事务的状态(回滚点、是否完成、是否新事务、是否回滚)属性,是一个过程值
  • 这个一般不需要关注
public interface TransactionStatus extends TransactionExecution
    , SavepointManager, Flushable {
    // 是否有保存点
  boolean hasSavepoint();

    // 
  void flush();
}

TransactionDefinition事务定义

  • 定义事务的名称、隔离级别、传播行为、超时时间长短、只读属性等
public interface TransactionDefinition {
// 定义了一些成员变量
  int PROPAGATION_REQUIRED = 0;
  int PROPAGATION_SUPPORTS = 1;
  int PROPAGATION_MANDATORY = 2;
  int PROPAGATION_REQUIRES_NEW = 3;
  int PROPAGATION_NOT_SUPPORTED = 4;
  int PROPAGATION_NEVER = 5;
  int PROPAGATION_NESTED = 6;
  int ISOLATION_DEFAULT = -1;
  int ISOLATION_READ_UNCOMMITTED = 1;
  int ISOLATION_READ_COMMITTED = 2;
  int ISOLATION_REPEATABLE_READ = 4;
  int ISOLATION_SERIALIZABLE = 8;
  int TIMEOUT_DEFAULT = -1;

// 下面是提供默认值和对应的方法
// jdk1.8之后才提供的default
  default int getPropagationBehavior() {
    return 0;
  }

  default int getIsolationLevel() {
    return -1;
  }

  default int getTimeout() {
    return -1;
  }

  default boolean isReadOnly() {
    return false;
  }

  @Nullable
  default String getName() {
    return null;
  }

  static TransactionDefinition withDefaults() {
    return StaticTransactionDefinition.INSTANCE;
  }
}

事务的传播行为

  • 指多个方法之间如何来共享事务:发生异常的情况,谁提交谁回滚
  • REQUIRED (默认的事务传播行为)
    • 一荣俱荣,同生共死
      • 要么一起提交,要么一起回滚
  • REQUIRES_NEW
    • 自私型
      • 部不会影响内部,内部会影响外围
    • 内部的方法更重要
  • NESTED
    • 无私型
      • 外围会影响内部,内部不会影响外围
    • 外部的方法更重要
  • 其他传播行为
传播行为 描述
PROPAGATION_SUPPORTS 支持当前事务,假设当前没有事务,就以非事务方式运行
PROPAGATION_MANDATORY 支持当前事务,假设当前没有事务,就抛出异常
PROPAGATION_NOT_SUPPORTED 以非事务方式运行操作。假设当前存在事务,就把当前事务挂起
PROPAGATION_NEVER 以非事务方式运行,假设当前存在事务,则抛出异常

eg:
在这里插入图片描述

  • config目录下的AppConfiguration注册组件
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
    transactionManager.setDataSource(dataSource);
    return transactionManager;
}
  • service目录下
    @Autowired
    PlatformTransactionManager platformTransactionManager;
    @Override
    public int transfer(Integer fromId, Integer destId, Double money) {

        Double fromMoney = accountMapper.selectByPrimaryKey(fromId) - money;
        Double destMoney = accountMapper.selectByPrimaryKey(destId) + money;

        // 开启事务
        TransactionStatus status = platformTransactionManager
                .getTransaction(TransactionDefinition.withDefaults());

        try {
            accountMapper.upDate(fromId, fromMoney);
            int i = 1 / 0;
            accountMapper.upDate(destId, destMoney);
        }catch (Exception e) {
            // 事务的回滚
            platformTransactionManager.rollback(status);
            e.printStackTrace();
        }

        // 提交事务并关闭
        platformTransactionManager.commit(status);

        return 0;
    }

TransactionTemplate

  • 事务的模板,采用事务模板提供的方法来使用事务
  • 对上面事务的传播行为做一系列的封装
  • 下图的绿色是需要写的业务代码
    在这里插入图片描述

eg:

  • config目录下的AppConfiguration注册组件
@Bean
public TransactionTemplate transactionTemplate(PlatformTransactionManager transactionManager) {
    TransactionTemplate transactionTemplate = new TransactionTemplate();
    transactionTemplate.setTransactionManager(transactionManager);
    return transactionTemplate;
}
  • service目录下
@Service
public class AccountServiceImpl implements AccountService {

    @Autowired
    AccountMapper accountMapper;

    @Autowired
    TransactionTemplate transactionTemplate;

    @Override
    public int transfer(Integer fromId, Integer destId, Double money) {

        Double fromMoney = accountMapper.selectByPrimaryKey(fromId) - money;
        Double destMoney = accountMapper.selectByPrimaryKey(destId) + money;


        TransactionCallback<Object> transactionCallback = new TransactionCallback<Object>() {
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                accountMapper.upDate(fromId, fromMoney);
                int i = 1 / 0;
                accountMapper.upDate(destId, destMoney);
                return null;
            }
        };

        transactionTemplate.execute(transactionCallback);

        return 0;
    }
}


Transactional注解

  • 采用AOP的方式给容器的组件生成代理对象
  • @Transactional注解的ElementType为TYPE和METHOD,意味着可以写在类上或方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}
  • 使用注解

    1. 使用注解前,需要先打开事务的注解驱动
    @Configuration
    @ComponentScan("com.coo1heisenberg.demo4")
    @EnableTransactionManagement
    public class AppConfiguration {}
    
    1. 直接使用@Transactional注解,可以使用注解提供的属性配置事务的TransactionDefinition
    @Service
    // @Transactional(readOnly = true)
    // @Transactional(timeout = 4)
    public class AccountServiceImpl implements AccountService {
    
    @Autowired
    AccountMapper accountMapper;
    
    @Override
    @Transactional
    public int transfer(Integer fromId, Integer destId, Double money) {
    
        Double fromMoney = accountMapper.selectByPrimaryKey(fromId) - money;
        Double destMoney = accountMapper.selectByPrimaryKey(destId) + money;
    
        accountMapper.upDate(fromId, fromMoney);
        int i = 1 / 0;
        accountMapper.upDate(destId, destMoney);
    
        return 0;
    	}
    }
    

上一篇:ppt从零基础到高手【办公】


下一篇:win11 如何把微软账户切换成administrator