Spring中的事务分为编程式事务和声明式事务
解释:
1.编程式事务,主要通过TransactionTemplate或TransactionManager手动管理事务,编程式事务作用于代码,可以选择某一行代码进行事务管理,需要手动开启、提交、回滚事务。也就是需要自己编写一下开启、提交和回滚事务的方法。
2.声明式事务,通过aop切面配置或者通过在类或者方法上加上@Transactional,也就是有通过注解的方案(@Transactional)和基于XML配置文件的方案(AspectJ框架)。声明式事务作用于方法或者类,在目标方法开始之前创建或者加入一个事务,在执行完目标方法之后根据执行情况提交或者回滚事务。
3.可以简单的理解为:编程式事务就是自己在业务逻辑种编写代码来管理事务,声明式事务是通过注解即配置的方式进行事务的管理
声明式事务所应用的范围较大和使用方式较简便,和编程式事务相比,声明式事务唯一不足的地方是:声明式事务的最细粒度只能作用到方法级别,无法像编程式事务那样可以作用到代码级别。但也可以通过将需要进行事务管理的代码块抽离成方法等等。
事务传播机制:
PROPAGATION_REQUIRED | 当存在事务,就加入事务 |
PROPAGATION_SUPPORTS | 当存在事务,就以事务方式运行,没有事务,就以非事务方式运行 |
PROPAGATION_MANDATORY | 当存在事务,就加入事务,如果没有事务,就抛出异常 |
PROPAGATION_REQUIRES_NEW | 创建一个新的事务,如果当前存在事务,就把当前事务挂起 |
PROPAGATION_NOT_SUPPORTED | 以非事务的方式运行,存在事务,则把当前事务挂起 |
PROPAGATION_NEVER | 以非事务的方式运行,存在事务,则抛出异常 |
PROPAGATION_NESTED | 当前存在事务,就嵌套一个事务,如果当前没有事务,则与PROPAGATION_REQUIRED相同,外层事务异常,会影响内部,但内部异常,并不会影响外部 |
编程式事务
项目中使用TransactionManager
使用过程:
1.首先在数据源中创建事务管理器
//代码可能拼写有误,注意辨别
@Configuration
@MapperScan(basePackages = {"com.dachun.mapper"}, sqlSessionFactoryRef = "sqlSessionFactory1")
public class MybatisDbAConfig {
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "spring.datasource.db1")
public DataSource creDataSource() {
return new DataSourceBuilder.create().build();
}
@Bean(name = "SqlSessionFactory")
public SqlSessionFactory creSqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
bean.setDataSource(dataSource);
return bean.getObject();
}
//创建事务管理器
@Bean(name = "TransactionManager")
public DataSourceTransactionManager transactionManager(@Qualifier("dataSource") DataSource dataSource) throws Exception {
return new DataSourceTransactionManager(dataSource);
}
@Bean(name = "SqlSessionTemplate")
public SqlSessionTemplate sqlSessionTemplate1(@Qualifier("SqlSessionFactory") SqlSessionFactory sqlSessionFactory ) throws Exception {
return SqlSessionTemplate(sqlSessionFactory);
}
}
2.在serviceImpl实现类中引入TransactionManager并使用
-
PlatformTransactionManager : 事务管理器
-
TransactionDefinition : 事务的一些基础信息,如超时时间、隔离级别、传播属性等
-
TransactionStatus : 事务的一些状态信息,如是否是一个新的事务、是否已被标记为回滚
TransactionManager是一个接口,并且是空接口。所以在具体的代码中,要用其的子类PlatformTransactionManager,在这个子类有且仅有三个方法,对应的功能分别是开启事务、提交事务和回滚事务。虽然在TbStudentServiceImpl中使用的是PlatformTransactionManager,但是在MybatisDbAConfig配置文件中使用的是DataSourceTransactionManager。
@Service
public class TbStudentServiceImpl extends ServiceImpl<TbStudentMapper, TbStudent> implements ITbStudentService {
@Resource(name = "TransactionManager")
private PlatformTransactionManager transactionManager;
@Override
public void selects(TbStudent tbStudent, int page, int pagesize) {
//定义默认事务 创建一个新的DefaultTransactionDefinition,使用默认设置。
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
// 设置事务传播机制
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_MANDATORY);
//开启事务 TransactionStatus接口让事务管理器控制事务的执行
TransactionStatus status= transactionManager.getTransaction(def);
try{
Page<TbStudent> tbStudent = new Page<>(page, pagesize);
tbStudentMapper.update(tbStudent);
//提交事务
transactionManager.commit(status);
}catch (Exception e){
transactionManager.rollback(status);
e.printStackTrace();
}
}
}
声明式事务
项目中使用@Transactional注解
@Transaction 可以写在类、接口、方法上
- 当标注在类上的时候:表示给该类所有的 public 方法添加上 @Transaction 注解
- 当标注在接口上的时候:Spring 建议不要在接口或者接口方法上使用该注解,因为这只有在使用基于接口的代理时它才会生效。像 CGLib 动态代理采用继承的方式将会导致 @Transactional 注解失效
- 当标注在方法上的时候:事务的作用域就只在该方法上生效,并且如果类及方法上都配置 @Transaction 注解时,方法的注解会覆盖类上的注解
使用过程:
1.首先@EnableTransactionManagement声明在主配置类上,表示开启声明式事务
@SpringBootApplication
@EnableTransactionManagement
public class ServerApplication {
public static void main(String[] args) {
SpringApplication.run(ServerApplication.class, args);
}
}
2.在serviceImpl实现类的方法上添加注解 @Transaction
propagation:可选的事务传播行为设置
isolation:可选的事务隔离级别设置
@Service
public class StudentServiceImpl extends ServiceImpl<TbStudentMapper, TbStudent> implements ITbStudentService {
@Autowired
TbStudentMapper tbStudentMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 120000, rollbackFor = Exception.class)
public IPage<TbStudent> selects(TbStudent tbStudent, int page, int pagesize) {
Page<TbStudent> pages = new Page<>(page, pagesize);
tbStudentMapper.selects(pages);
}
}
手动回滚
spring 也提供了 @Transaction 对应的手动回滚方式
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();