07-Spring的事务处理

Posted on 2021-07-05 00:56  萌栈师  阅读(87)  评论(0编辑  收藏  举报

Spring中提供了七种事务的传播行为:

PROPAGATION_REQUIRED:默认值,最常用,统一事务,出现异常,全部回滚

其余参考Spring事务处理word文档。

0、原转账业务(不含事务处理)

MyAspect:

@Component
public class MyAspect {
    @Autowired
    UserMapper userMapper;
    @Autowired
    AccountMapper accountMapper;

    /**
     * 判断是否能转账
     * @param point 切入点
     * @return 1 可以转账
     */
    public int transAccount(ProceedingJoinPoint point){
        //拿到切入点参数
        Object[] args = point.getArgs();
        //转出人id
        int outId = (int)args[0];
        //转账金额
        double money = (double)args[2];
        //转出人cid
        int cidOut = userMapper.getCidById(outId);
        //获取转出人账户余额
        double balance = accountMapper.getMoney(cidOut);
        //判断转出的账户余额与转出金额比较
        //转出>余额  异常:余额不足
        if (money>balance){
            throw new RuntimeException("余额不足,转账失败");
        }else {
            //执行转账
            try {
                int i = (int)point.proceed();
                return i;
            } catch (Throwable throwable) {
                throwable.printStackTrace();
            }
        }
        return 0;
    }
}

通过aop编程,给原转账业务增加上面的增强类方法(基于xml):

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <aop:config>
        <aop:pointcut id="p1" expression="execution(* com.yd.service.impl.AccountServiceImpl.transferAccountIn(..))"/>

        <aop:aspect ref="myAspect">
            <aop:around method="transAccount" pointcut-ref="p1"></aop:around>
        </aop:aspect>
    </aop:config>

<!--    强制使用cglib代理-->
    <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>

</beans>

一、基于xml的事务

通过AOP编程,给转账业务添加事务处理功能

  • 在转账是可能出现时间延时或其他异常,导致事务不统一
  • 以下用aop方式,给转账业务添加事务
    • 在不用更改源代码的情况下添加事务处理

transaction.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

    <!-- 配置事物管理器的切面 -->
    <bean id="transactionMananger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!-- 配置事物传播行为 :其实就是哪些方法应该受什么样的事物控制-->
    <tx:advice id="advice" transaction-manager="transactionMananger">
        <tx:attributes>
            <tx:method name="transferAccountIn" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>

    <!-- 哪些类下的方法需要参与到当前的事物管理中,配置切入点 -->
    <aop:config>
        <aop:advisor advice-ref="advice" pointcut="execution(* com.yd.service.impl.AccountServiceImpl.*(..))"/>
    </aop:config>
</beans>

切入点-AccountServiceImpl:

@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    AccountMapper accountMapper;

    @Autowired
    UserMapper userMapper;

    @Override
    public int transferAccountIn(int idOut, int idIn, double money) {
        //转入人cid
        int cidIn = userMapper.getCidById(idIn);
        //转入金额
        int in = accountMapper.updateIn(cidIn,money);
        //模拟异常
        System.out.println(1/0);
        //转出人cid
        int cidOut = userMapper.getCidById(idOut);
        //转出金额
        int out = accountMapper.updateOut(cidOut,money);

        return in + out;
    }
}
  • 将事务添加在transferAccountIn()方法上,只要有异常,其中的事务全部回滚

运行代码:

public class Demo {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("mybatis.xml", "spring.xml","aspect.xml","tansaction.xml");
        AccountServiceImpl accountServiceImpl = (AccountServiceImpl)ac.getBean("accountServiceImpl");
        int res = accountServiceImpl.transferAccountIn(2,1,900);
        if (res==2){
            System.out.println("转账成功!");
        }else {
            System.out.println("转账失败!");
        }
    }
}

运行结果:

  • 出现异常,事务回滚

二、基于注解的事务

1. 在transacion.xml配置文件中添加:开启注解事务

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- bean definitions here -->

    <!-- 配置事物管理器的切面(必须要) -->
    <bean id="transactionMananger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>  <!--强制使用Cglib代理-->
<!--    开启注解事务-->
    <tx:annotation-driven transaction-manager="transactionMananger"></tx:annotation-driven>
</beans>

2.在相应的方法上添加注解

@Transactional(propagation = Propagation.REQUIRED)

  • 在类上加此注解,表示当前类下所有方法都参与指定的事务管理
  • 在方法上加此注解,表示该方法执行指定的事务管理
@Service
public class AccountServiceImpl implements AccountService {
    @Autowired
    AccountMapper accountMapper;

    @Autowired
    UserMapper userMapper;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public int transferAccountIn(int idOut, int idIn, double money) {
        //转入人cid
        int cidIn = userMapper.getCidById(idIn);
        //转入金额
        int in = accountMapper.updateIn(cidIn,money);
        System.out.println(1/0);
        //转出人cid
        int cidOut = userMapper.getCidById(idOut);
        //转出金额
        int out = accountMapper.updateOut(cidOut,money);

        return in + out;
    }
}

运行代码(与前面一致):

public class Demo {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("mybatis.xml", "spring.xml","aspect.xml","tansaction.xml");
        AccountServiceImpl accountServiceImpl = (AccountServiceImpl)ac.getBean("accountServiceImpl");
        int res = accountServiceImpl.transferAccountIn(2,1,900);
        if (res==2){
            System.out.println("转账成功!");
        }else {
            System.out.println("转账失败!");
        }
    }
}

运行结果:

同样会出现异常,回滚

  • 注解开发更方便
  • 需要修改源码,在源码上加注解

Copyright © 2024 萌栈师
Powered by .NET 8.0 on Kubernetes