目录
Spring事务简介
Spring支持事务管理的两种方式
编程式事务控制
声明式事务管理
Spring事务角色
未开启事务之前
开启Spring的事务管理后
事务配置
事务传播行为
事务传播行为的可选值
Spring事务简介
事务作用:在数据层保障一系列的数据库操作同成功同失败
Spring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败
需要注意的是:
程序是否支持事务首先取决与数据库,比如使用MySQL的,且选择的是innodb引擎,那么是可以支持事务的。但是,如果选择的是myisam引擎的话,那么从根本上就是不支持事务的,即使Spring中设置了事务,也不会生效。
Spring支持事务管理的两种方式
编程式事务控制
在源代码中编辑事务的逻辑流程,也就是在代码中设置动态信息,开启事务,提交事务,回滚事务
编程式事务控制通过TransationTemplate或者TransactionManager手动管理事务
声明式事务管理
实际是通过AOP实现,且基于@Transactional的全注解的方式也是使用最多的
使用声明式事务官的实现步骤:
步骤一:在需要被事务管理的方法上添加注解
@Transactional可以写在接口类上、接口方法上、实现类上和实现类方法上
-
写在接口类上,该接口的所有实现类的所有方法都会有事务
-
写在接口方法上,该接口的所有实现类的该方法都会有事务
-
写在实现类上,该类中的所有方法都会有事务
-
写在实现类方法上,该方法上有事务
-
建议写在实现类或实现类的方法上
步骤二:在jdbcConfig类中配置事务管理器
//配置事务管理器,mybatis使用的是jdbc事务
@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource){
DataSourceTransactionManager transactionManager = new DataSourceTransactionManager();
transactionManager.setDataSource(dataSource);
return transactionManager;
}
注意:事务管理器要根据使用技术进行选择,Mybatis框架使用的是JDBC事务,可以直接使用
DataSourceTransactionManager
步骤三:开启事务注解
在SpringConfig的配置类中开启
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:jdbc.properties")
@Import({JdbcConfig.class,MybatisConfig.class
//开启注解式事务驱动
@EnableTransactionManagement
public class SpringConfig {
}
设置好后运行测试类,就可以发现当业务出现错误后,事务就可以控制回滚,保证数据的正确性
Spring事务角色
未开启事务之前
- AccountDao 的outMoney因为是修改操作,会开启一个事务T1
- AccountDao 的inMoney因为是修改操作,会开启一个事务T2
- AccountService的transfer没有事务
执行后如果运行过程中没有抛异常,则T1heT2都正常提交,数据正确
如果两个方法中出现异常,T1执行成功提交事务,但T2因为抛异常不会执行,则就导致数据出现错误
开启Spring的事务管理后
-
transfer上添加了@Transactional注解,在该方法上就会有一个事务T
-
AccountDao的outMoney方法的事务T1加入到transfer的事务T中
-
AccountDao的inMoney方法的事务T2加入到transfer的事务T中
-
这样就保证他们在同一个事务中,当业务层中出现异常,整个事务就会回滚,保证数据的准确性。
由上述可知:
- 事务管理员:发起事务方,在Spring中通常指代业务层开启事务方法
- 事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法
注意:目前的事务管理是基于DataSourceTransactionManager
和SqlSessionFactoryBean
使用的是同一个数据源。
事务配置
以上这些属性都可以在@Transactional注解的参数上进行设置
-
readOnly:true只读事务,false读写事务,增删改要设为false,查询设为true。
-
timeout:设置超时时间单位秒,在多长时间之内事务没有提交成功就自动回滚,-1表示不设置超时时间。
-
rollbackFor:当出现指定异常进行事务回滚
-
noRollbackFor:当出现指定异常不进行事务回滚
并不是所有的异常都会回滚事务,所以需要rolbackFor的存在,比如下列代码:
@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(); //这个异常事务就不会回滚
}
accountDao.inMoney(in,money);
}
上述代码中不会出现回滚的的原因是:
Spring的事务只会对Error异常和RuntimeException异常及其子类进行事务回滚,其他的异常类型是不会回滚的,对应IOException不符合以上的条件,所以不回滚
此时就可以使用rollabckFor属性来设置出现IOException异常不回滚
@Transactional(rollbackFor = {IOException.class})
此时 throw new IOException(); 这个异常事务就不会回滚
@Transactional的常用配置参数
属性名 | 说明 |
---|---|
propagation | 事务的传播行为,默认值为 REQUIRED |
isolation | 事务的隔离级别,默认值采用 DEFAULT,可选的值
|
timeout | 事务的超时时间,默认值为-1(不会超时)。如果超过该时间限制但事务还没有完成,则自动回滚事务。 |
readOnly | 指定事务是否为只读事务,默认值为 false。true只读事务,false读写事务,增删改要设为false,查询设为true。 |
rollbackFor | 用于指定能够触发事务回滚的异常类型,并且可以指定多个异常类型。 |
noRollbackFor | 事务的传播行为,默认值为 REQUIRED,可选的值在上面介绍过 |
事务传播行为
加入一个记录日志的功能,事务T2也会加入到事务T中(因为事务传播行为的默认值为REQUIRED,所以此时虽然有@Transaction开启了事务T2还是会加入到事务T中)
若此时转账失败,所有事务回滚,导致日志中没有任何关于此次转账的信息,这显然是不行的;
此时,需修改logService改变事务的传播行为,通过@Transaction中的可选属性进行配置:
@Autowired
private LogDao logDao;
//propagation设置事务属性:传播行为设置为当前操作需要新事务
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void log(String out,String in,Double money ) {
logDao.log("转账操作由"+out+"到"+in+",金额:"+money);
}
事务传播行为的可选值