Spring的事务操作

事务是数据库操作的最基础单元,参考TCL

典型场景:转账业务

A→B转账100,A-100&&B+100,两者同时满足则完成转账操作,两者相互依赖,如果只有一个满足/不满足则是bug,因此这种业务必须以事务来控制

1. Spring事务管理API

在这里插入图片描述

2. 编程式事务管理

@Autowired
private JdbcTemplate jdbcTemplate;

@Autowired
private DataSourceTransactionManager txManager;
private void test(){
  //默认事务定义:隔离级别,传播行为等参数,参考声明式事务管理参数
  TransactionDefinition tf = new DefaultTransactionDefinition();
  //开启事务
  TransactionStatus ts = txManager.getTransaction(tf);
  try {
      //事务处理
      boolean reduceFlag = userDao.reduceMoney(reduce);
      int i = 1 / 0;
      boolean addFlag = userDao.addMoney(add);

      txManager.commit(ts);
  }catch (Exception e){
      //回滚
      txManager.rollback(ts);
  }
}

3. 声明式事务管理(AOP)

声明式事务管理需要在连接数据库后做三件事

  1. 注入事务管理器

  2. 在事务管理器中注入数据源

  3. 开启事务

3.1 注解方式

注解方式分为两种,一种是半注解方式;一种是完全注解方式

半注解方式

需要在xml配置文件中开启事务注解

  1. 配置事务管理器

    <!--创建事务管理器-->
    <bean id ="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        
    </bean>
    
  2. 注入数据源

    <!--创建事务管理器-->
    <bean id ="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
  3. 开启事务注解

    xmlns:tx="http://www.springframework.org/schema/tx"
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
    
    <!--开启事务注解-->
    <tx:annotation-driven transaction-manager="transactionManager"/>
    
  4. 使用注解

    @Transactional:事务注解,可用于方法或类上

    1. 在方法上表示当前方法具有事务的特性

    2. 在类上表示当前类中所有方法都具有事务的特性
      在这里插入图片描述
      完全注解方式

配置类配置:

  1. 配置数据库连接池

    //创建数据库连接池
    @Bean
    public DruidDataSource getDruidDataSource(){
        Properties pro=new Properties();
        try {
            pro.load(new FileReader("src/jdbc.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(pro.getProperty("driverClass"));
        dataSource.setUrl(pro.getProperty("url"));
        dataSource.setUsername(pro.getProperty("name"));
        dataSource.setPassword(pro.getProperty("password"));
        return dataSource;
    }
    
  2. 注入JdbcTemplate对象

    //创建JDBCTemplate对象:这里的参数dataSource是根据Spring注入了DataSource以后,从Spring容器中获取的参数
    @Bean
    public JdbcTemplate getJdbcTemplate(DataSource dataSource){
        JdbcTemplate jdbcTemplate=new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
    
  3. 创建事务管理器对象

    //创建事务管理器的对象
    @Bean
    public DataSourceTransactionManager getDataSourceTransactionManager(DataSource dataSource){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        //注入dataSource实例
        dataSourceTransactionManager.setDataSource(dataSource);
        return dataSourceTransactionManager;
    }
    
  4. 开启事务

    @EnableTransactionManagement
    public class SpringConfig{
    

    调用测试

    ApplicationContext context=new AnnotationConfigApplicationContext(SpringConfig.class);
    UserController userController = context.getBean("userController", UserController.class);
    
3.2 xml配置方式

需要在xml配置文件中声明命名空间

在这里插入图片描述

  1. 配置事务管理器

    <!--创建事务管理器-->
    <bean id ="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        
    </bean>
    
    <!--创建事务管理器-->
    <bean id ="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <!--注入数据源-->
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
  2. 配置通知

    <tx:advice id = "txAdvice">
        <!--配置事务参数-->
        <tx:attributes>
            <tx:method name="swapBatch" rollback-for="Exception.class"/>
        </tx:attributes>
    </tx:advice>
    
  3. 配置切入点和切面

    <!--配置切入点和切面:在哪个方法上使用该事务-->
    <aop:config>
        <!--切入点-->
        <aop:pointcut id="pt" expression="execution(* com.carl.service.impl.UserServiceImpl.swapBatch(..))"/>
        <!--切面-->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
    </aop:config>
    

4. 声明式事务管理的参数

在这里插入图片描述

参数说明参数值参数值说明使用场景
value用于指定不同的事务管理器事务管理器id在项目中使用的事务管理器id值使用场景:同一个系统中存在不同的事务管理器,例如Spring中可声明两种事务管理器
propagation传播行为:当方法A是事务,方法B是事务,且方法A调用方法B时方法B的事务状态称为事务的传播行为Propagation.REQUIRED如果有事务在运行,当前的方法就在这个事务内运行,否则就启动一个新的事务,并在自己的事务内运行如果方法A调用方法B,此时方法B有此注解参数,则如果当方法A中有事务,则方法B与方法A处在同一个事务内,否则如果方法A没有事务,则方法B会在自己的事务内运行
Propagation.REQUIRED_NEW当前方法必须启动新的事务,并在自己的事务内运行,如果有事务正在运行,应该将它挂起如果方法A调用方法B,此时方法B中有此注解,则如果当方法A中有事务,方法B也必须在自己的事务中运行,方法A和方法B的事务互不影响,如果方法A触发事务在前,则方法B挂起等待方法A执行完成后再执行方法B
Propagation.SUPPORTS如果有事务在运行,当前的方法就在这个事务内运行,否则它可以不运行在事务中如果方法A调用方法B,此时方法B中有此注解,则如果当方法A中有事务,则方法B也在当前事务中统一运行,如果方法A中没有事务,则方法B也没有事务
Propagation.NOT_SUPPORTED当前的方法不应该运行在事务中,如果有运行的事务,当前方法挂起如果方法A调用方法B,此时方法B中有此注解,则如果方法A中有事务,则执行方法A的事务,方法B将会等待方法A事务执行完成后执行,当前方法B不应该运行在事务中
Propagation.MANDATORY当前方法必须运行在事务的内部,如果没有正在运行的事务,就抛出异常如果方法A调用方法B,此时方法B中有此注解,则如果方法A中有事务,方法B将会在当前事务内执行,如果方法A中没有事务,方法B将会抛出异常
Propagation.NEVER当前方法不应该运行在事务中,如果有运行的事务,就抛出异常如果方法A调用方法B,此时方法B中有此注解,则如果方法A中有事务,方法B抛出异常,如果方法A中没有事务,方法B正常执行
Propagation.NESTED如果有事务在运行,当前的方法就应该在这个事务的嵌套事务内运行,否则就启动一个新的事务,并在它自己的事务内运行如果方法A调用方法B,此时方法B中有此注解,则如果方法A中有事务,则方法B作为该事务的嵌套事务执行,即作为当前事务的子事务,如果方法A中没有事务,则方法B自己创建新的事务运行
ioslation事务的隔离级别READ UNCOMMITTED读未提交不会对当前问题做任何处理
READ COMMITTED读已提交无脏读问题
REPEATABLE READ可重复读(MySQL默认隔离级别)无脏读&&无可重复读
SERIALIZABLE串行化无脏读&&无可重复读&&无幻读
timeout超时时间timeout =2秒为单位(默认为-1)当前事务在两秒内未提交则回滚并抛出异常
rollbackFor回滚rollbackFor = Exception.class设置出现哪些异常进行回滚有些异常直接或间接影响数据,有必要进行回滚,通过该参数进行设置
noRollbackFor不回滚noRollbackFor = NullException.class设置出现哪些异常不需要回滚有些异常不会影响数据的增删改查以及数据的真实性,通过该参数进行设置避免回滚
readOnly是否只读readOnly = true默认为falsetrue:表示当前事务只能进行查询操作
false:表示当前事务可以进行增删改查等操作

嵌套事务:是指子事务在父事务中执行

  • 在进入子事务前,父事务会建立一个回滚点(save point),执行完子事务后父事务继续执行.

  • 如果子事务回滚,父事务会回滚到save point,然后尝试后续的操作或业务,父事务之前的事务并不会受到影响

  • 如果父事务回滚,子事务也会回滚,父事务结束之前,子事务不会提交.

  • 父事务和子事务的提交顺序:子事务先提交,父事务后提交

  • 10
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值