Spring事务

1.1Spring事务简介

  • 事务作用:在数据层保障一系列的数据库操作同成功或同失败
  • Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功或同失败
public interface PlatformTransactionManager{
	void commit(TransactionStatus status) throws TransactionException;
	void rollback(TransactionSattus status) throws TransactionException;
}
public class DataSourceTransactionManager{
	...
}

1.2案例:银行账户转账

模拟银行账户间转账业务

需求:实现任意两个账户间转账操作

需求微缩:A账户减钱,B账户加钱

分析:

  1. 数据层提供基础操作,指定账户减钱(outMoney),指定账户加钱(inMoney)
  2. 业务层提供转账操作(transfer),调用减钱和加钱的操作
  3. 提供2个账号和操作金额执行转账操作
  4. 基于Spring整合MyBatis环境搭建上述操作

结果分析:

  1. 程序正常执行时,账号金额A减B加,没有问题
  2. 程序出现异常,转账失败,单是异常之前操作成功,异常之后操作失败,整体业务失败

案例实现步骤:

①在业务层接口上添加Spring事务管理

public interface AccountService{
	@Transactional
	public void transfer(String out,String in,Double money);
}

说明:Spring注解式事务通常添加在业务层接口中,相比于添加到业务层的实现类中,Spring在这一点上也做到了降低耦合  

注解式业务可以添加到业务方法上表示开启事务,也可以添加到接口上表示当前接口所有方法开启事务

②设置事务管理器

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSoure){
	DataSouceTransactionManager ptm = new DataSourceTransactionManager();
	ptm.setDataSource(dataSource);
	return ptm;
}

注意:事务管理器要根据实现技术进行选择,Mybatis框架使用的是JDBC事务

③开启注解式事务驱动

@Configuration
@ComponentScan("com.hcx")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class})
@EnableTransactionManagement
public class SpringConfig{
}

1.3事务角色

  • 事务角色
    • 事务管理员:发起事务方,在Spring中通常指代业务层开启事务的方法
    • 事务协调员:加入事务方,在Spring中通常带着数据层方法,也可以是业务层方法

未开启Spring事务之前的工作流程

 

数据层中的AccountDao中的outMoney、inMoney是修改操作,会各自开启一个事务T1、T2
业务层中的AccountService的transfer没有事务

运行过程中如果没有抛出异常,则T1和T2都正常提交,数据正确
若在方法1之后和方法2之前出现异常,事务T1会执行成功提交事务,事务T2因为抛异常不会被执行就会导致数据出现错误

开启Spring事务之后的工作流程

transfer上添加了@Transactional注解,则该方法上就会添加一个事务T
outMoney()的事务T1\inMoney()的事务T2均加入到transfer的事务T中
使他们在同一个事务中,当业务层中出现异常,整个事务就会回滚,从而保证数据的准确性。

注:Mybstis配配置类中SqlSessionFactoryBean和JDBC配置类中的事务管理器DataSourceTransactionManager中是同一个dataSource,因此才可以做到统一管理,即同通过相同数据源进行管理

事务相关配置

readOnly:设置只读事务。true只读事务,false读写事务,增删改要设为false,查询设为true,默认设置为false即读写事务。

timeout:设置事务超时时间。单位秒,在timeout之内事务没有提交成功就自动回滚,-1表示永不超时。

rollbackFor:当出现指定异常进行事务回滚

public interface AccountService {
    /**
     * 转账操作
     * @param out 传出方
     * @param in 转入方
     * @param money 金额
     */
    //配置当前接口方法具有事务
    public void transfer(String out,String in ,Double money) throws IOException;
}
 
@Service
public class AccountServiceImpl implements AccountService {
 
    @Autowired
    private AccountDao accountDao;

    @Transactional
    public void transfer(String out,String in ,Double money) throws IOException{
        accountDao.outMoney(out,money);
        //int i = 1/0; //这里异常事务会回滚
        if(true){
            throw new IOException(); //这里的IO异常事务默认不会参与回滚
        }
        accountDao.inMoney(in,money);
    }
 
}
@Service
public class AccountServiceImpl implements AccountService {
 
    @Autowired
    private AccountDao accountDao;
    //设置IOException回滚异常
     @Transactional(rollbackFor = {IOException.class})
    public void transfer(String out,String in ,Double money) throws IOException{
        accountDao.outMoney(out,money);
        //int i = 1/0; 
        if(true){
            throw new IOException(); //加上roollbackFor之后异常事务回滚
        }
        accountDao.inMoney(in,money);
    }
 
}

注:使用rollbackFor属性来设置出现IOException异常回滚

noRollbackFor:当出现指定异常不进行事务回滚

1.4案例:转账业务追加日志

需求分析:实现任意两个账户间转账操作,并对每次转账操作在数据库进行留痕

需求微缩:A账户减钱,B账户加钱,数据库记录日志

分析:

基于转账操作案例添加日志模块,实现数据库中记录日志
业务层转账操作(transfer),调用减钱,加钱与记录日志功能
实现效果预期:

无论转账是否成功,均进行转账操作的日志留痕

存在问题:

日志的记录与转账操作隶属于同一事务,同成功同失败

失效效果预取改进:

无论转账操作是否成功,日志必须保留,需要设置事务传播行为propagation

事务传播行为------propagation属性:事务协调员对事务管理员所携带事务的处理态度

日志记录失败原因分析: log方法、inMoney方法和outMoney方法都属于增删改各自开启事务T1,T2,T3且都属于事务协调员,transfer加了@Transactional注解,也开启了事务T,且属于事务管理员,事务管理员T会把事务协调员T1,T2,T3都加入到事务T中
这样一来,当转账失败时,事务T一旦发生回滚,则所有的事务都会回滚,造成日志没有记录
改进实现

修改logService改变事务的传播行为propagation属性Propagation.REQUIRES_NEW

REQUIRES_NEW实现新建一个事务

@Service
public class LogServiceImpl implements LogService {
    @Autowired
    private LogDao logDao;
    //propagation设置事务属性:传播行为设置为当前操作建立新事物,不和其他人一起玩
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void log(String out,String in,Double money ) {
        logDao.log("转账操作由"+out+"到"+in+",金额:"+money);
    }
}

事务传播行为总结:

说明:
PROPAGATION_REQUIRED    如果事务管理员没有事务,就新建一个事务,如果事务管理员已经存在一个事务中,加入到这个事务中。
PROPAGATION_SUPPORTS    支持当前事务,如果当前事务管理员没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY    使用当前的事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW    新建事务,如果当前事务管理员存在事务,则事务协调员新建一个事务;否则,仍然新建一个事务,无论如何就是自己玩。
PROPAGATION_NOT_SUPPORTED    以非事务方式执行操作,如果当前事务管理员存在事务,事务协调员不加入,如果当前事务管理员未开启事务,同样不开启事务。
PROPAGATION_NEVER    以非事务方式执行,如果当前事务管理员存在事务,则抛出异常。
PROPAGATION_NESTED    如果当前事务管理员存在事务,则在嵌套事务内执行。如果当前没有事务,则执行与PROPAGATION_REQUIRED类似的操作。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值