【归纳总结】Spring之事务

核心接口

1️⃣PlatformTransactionManager

平台事务管理器,依赖于数据源,可以保证拿到的是同一个connection

有三个api:

  • getTransaction:通过事务定义获得事务状态
  • commit:提交事务
  • rollback:回滚事务

2️⃣TransactionStatus

记录事务状态
在这里插入图片描述

3️⃣TransactionDefinition

事务的名称、事务的隔离级别、事务的传播行为、事务的只读状态、事务的超时时间

三者之间的关系如图:
在这里插入图片描述


传播行为

实现多个事务的共享,当方法之间存在调用关系时候,应该如何提交事务,发生异常时是否回滚

例如:methodB调用到了methodA

methodA(){
	//method1里的内容
}
methodB(){
	//method2里的内容
	methodA();
}

有三种常用的传播行为

1️⃣REQUIRED(默认值)

如果没有事务就创建一个,如果包含了事务,则加入进来 → 作为一个事务
一荣俱荣、一损俱损:要么一起提交,要么一起回滚

在上述例子中:
如果methodB的代码发生异常:AB都回滚
如果methodA的代码发生异常:AB都回滚

2️⃣REQUIRES_NEW

如果没有事务就新建一个,如果包含事务,则以一个新事务的形式存在
自私型事务:别人不能影响我,但是我可以影响别人;外围不能影响内部,内部可以影响外围

上述例子中:
如果methodB的代码发生异常:B回滚、A不回滚
如果methodA的代码发生异常:A回滚、B也回滚

3️⃣NESTED

如果没有事务就新建一个,如果包含事务,则以嵌套事务的方式运行
无私型:外围会影响内部,内部不会影响外围。

上述例子中:
如果methodB的代码发生异常:B回滚、A也回滚
如果methodA的代码发生异常:A回滚、B不回滚


使用事务

使用事务实际上就是给特定的方法(代码)做一个“事务”的增强。

例如,现在有个转账业务:
根据两个人的id,和要转的钱,实施转账业务

@Service
public class AccountServiceImpl implements AccountService{

    @Autowired
    AccountMapper accountMapper;


    @Override
    public void transfer(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountMapper.selectMoneyById(fromId) - money;
        Integer destMoney = accountMapper.selectMoneyById(destId) + money;

        accountMapper.updateMoneyById(fromMoney, fromId);
        //int i = 1/0; 
        accountMapper.updateMoneyById(destMoney, destId);
    }
}

上述如果不做处理,发生异常时,就可能发生转账者钱扣了,但是收款者钱没有增加得情况。事务增强可以避免这种情况。

事务增强的方式有多种:

都需要TransactionManager

    <!--TransactionManager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>

ref就是dataSource组件的id,见文章:dataSource

1️⃣TransationTemplate(了解)

第一步

配置:

    <!--TransactionManager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
    
    <!--TransactionTemplate-->
    <bean class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>

第二步

在 transactionTemplate上调用execute方法,哪部分需要增加事务,就把哪部分丢到execute方法方法中

@Service
public class AccountServiceImpl implements AccountService{

    @Autowired
    AccountMapper accountMapper;

    @Autowired
    TransactionTemplate transactionTemplate;

    @Override
    public void transfer(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountMapper.selectMoneyById(fromId) - money;
        Integer destMoney = accountMapper.selectMoneyById(destId) + money;

        /*Object execute = transactionTemplate.execute(new TransactionCallback<Object>() {
            //哪一部分需要增加事务,哪部分代码就放入到doInTransaction方法中
            //doInTransaction方法的返回值 → 给到TransactionTemplate的execute方法
            @Override
            public Object doInTransaction(TransactionStatus transactionStatus) {
                accountMapper.updateMoneyById(fromMoney, fromId);
                //int i = 1 / 0;
                accountMapper.updateMoneyById(destMoney, destId);
                return 5;
            }
        });
        System.out.println(execute);*/
        
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {
                accountMapper.updateMoneyById(fromMoney, fromId);
                int i = 1/0;
                accountMapper.updateMoneyById(destMoney, destId);
            }
        });
    }
}

2️⃣TransactionProxy

与SpringAOP类似,通过委托类组件生成一个事务代理组件

第一步

配置:

    <!--TransactionManager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
    <!--委托类组件accountServiceImpl-->
    <!--代理组件-->
    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <property name="target" ref="accountServiceImpl"/>
        <property name="transactionManager" ref="transactionManager"/>
        <!--TransactionAttributes → TransactionDefinition-->
        <property name="transactionAttributes">
            <!--properties类型:既要表达key,又要表达value-->
            <props>
                <!--
                    key的含义:方法名
                    value的含义:TransactionDefinition
                    PROPAGATION_XXX:传播行为
                    ISOLATION_XXX:隔离级别
                    readOnly:只读
                    timeout_数字:超时时间,单位是秒
                    -Exception:当发生XXX异常的时候回滚
                    +Exception:当发生xxx异常是不回滚
                -->
                <prop key="transfer">PROPAGATION_REQUIRED,ISOLATION_DEFAULT,timeout_5</prop>
            </props>
        </property>
    </bean>

配置完后会在Spring容器中生成一个accountServiceImpl的代理类,id为刚刚在配置中写的“accountServiceProxy”

配置完就可以直接使用代理类了

但使用此方法会给委托类的所有方法加上事务增强

3️⃣Advisor

可以给指定范围内的方法加上事务增强

第一步

配置:
注意需要引入tx的schema

<!--TransactionManager-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>

    <aop:config>
        <aop:pointcut id="txPointcut" expression="execution(* com..service..*(..))"/>
        <!--事务通知组件-->
        <aop:advisor advice-ref="transactionAdvice" pointcut-ref="txPointcut"/>
    </aop:config>

    <!--tx:advice-->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <!--method definition-->
        <tx:attributes>
            <tx:method name="transfer*" propagation="REQUIRED" isolation="REPEATABLE_READ" read-only="false" timeout="5"/>
        </tx:attributes>
    </tx:advice>

4️⃣Annotation-driven重点

精准打击,指哪打哪——注解在哪个方法上,哪个方法就加上事务增强

第一步

配置:

    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="datasource"/>
    </bean>
    <tx:annotation-driven transaction-manager="transactionManager"/>

第二步

在方法上加注解

@Service
public class AccountServiceImpl implements AccountService{

    @Autowired
    AccountMapper accountMapper;
    
    @Override
    @Transactional
    public void transfer(Integer fromId, Integer destId, Integer money) {
        Integer fromMoney = accountMapper.selectMoneyById(fromId) - money;
        Integer destMoney = accountMapper.selectMoneyById(destId) + money;

        accountMapper.updateMoneyById(fromMoney, fromId);
        //int i = 1/0; 
        accountMapper.updateMoneyById(destMoney, destId);
    }
}

也可以加在类上,意味着当前组件的全部方法都加上事务增强

也可以通过给@Transactional注解的一些属性赋值来指定事务增强

如:

@Transactional(isolation = Isolation.REPEATABLE_READ,
            propagation = Propagation.REQUIRED,
            readOnly = true,
            timeout = 5)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值