文章目录
事务管理
1 事务回顾
事务是一组操作的集合,它是一个不可分割的工作单位,这些操作 要么同时成功,要么同时失败。
开启事务(一组操作开始前,开启事务):start transaction / begin ;
提交事务(这组操作全部成功后,提交事务):commit ;
回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;
2 转账案例
2.1 添加账户表
-- 创建账户表,并且添加两条测试数据
create table account (
id int primary key auto_increment,
name varchar(32),
balance float
);
insert into account (name, balance) VALUES ('A', 1000), ('B', 1000);
2.2 导入工程
导入maven工程
2.3 添加持久层代码
public interface AccountMapper {
//账户加钱
@Update("update account set balance = balance + #{money} where name = #{name}")
void add(@Param("name") String name,@Param("money") float money);
//账户减钱
@Update("update account set balance = balance - #{money} where name = #{name}")
void diff(@Param("name") String name,@Param("money") float money);
}
2.4 添加业务层代码
public interface AccountService {
//转账
//out 转出账户名
//in 转入账户名
//money 金额
void transfer(String out,String in,Float money);
}
@Service
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountMapper accountMapper;
@Override
public void transfer(String out, String in, Float money) {
//1.转出
accountMapper.diff(out,money);
//模拟报错
int i = 1/0;
//2.转入
accountMapper.add(in,money);
}
}
2.5 测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransFer(){
accountService.transfer("A","B",10F);
}
}
测试结果:java.lang.ArithmeticException: / by zero(除0错误)
数据库A的金额被修改,但是B没有被修改
A: 990
B:1000
2.6 问题
即使程序运行抛出了异常,转出账户的钱扣除了,但是转入账户的钱没加上,造成了数据的不一致。
3 事务管理
注解:@Transactional
位置:业务(service)层的方法上、类上、接口上
作用:将当前方法交给spring进行事务管理,方法执行前,开启事务;成功执行完毕,提交事务;出现异常,回滚事务
3.1 配置事务管理器
//配置类
@ComponentScan("com.itheima")
@EnableTransactionManagement//开启声明式事务管理
public class SpringConfig {
//向Spring容器放入事务管理器
//这个对象的id必须是transactionManager
@Bean
public DataSourceTransactionManager transactionManager(DruidDataSource dataSource){
DataSourceTransactionManager manager = new DataSourceTransactionManager();
manager.setDataSource(dataSource);
return manager;
}
3.2 添加事务注解
在转账方法上添加@Transactional注解,注意方法中要模拟异常
@Transactional //事务处理注解(可以标注在方法上,类上,接口上)
@Override
@Transactional //事务处理注解(可以标注在方法上,类上,接口上)
public void transfer(String out, String in, Float money) {
//1.转出
accountMapper.diff(out,money);
//模拟报错
int i = 1/0;
//2.转入
accountMapper.add(in,money);
}
3.3 测试
```java
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceTest {
@Autowired
private AccountService accountService;
@Test
public void testTransFer(){
accountService.transfer("A","B",10F);
}
}
测试结果:java.lang.ArithmeticException: / by zero(除0错误)
因为出现报错.事务回滚,数据库没有被修改
4 事务属性
4.1 rollbackFor(回滚)
默认情况下,只有出现 RuntimeException 才回滚异常,rollbackFor属性用于控制让非运行时异常也回滚。
@Override
//事务处理注解(可以标注在方法上,类上,接口上)
@Transactional(rollbackFor = Exception.class) //默认是在RuntimeException才回滚
public void transfer(String out, String in, Float money) throws Exception {
//1.转出
accountMapper.diff(out,money);
//模拟报错
if(true){
throw new Exception("出错啦");
}
//2.转入
accountMapper.add(in,money);
}
测试结果:
出现Exception错误,事务回滚
4.2 propagation(传播)
propagation称为事务传播行为,表示当一个事务方法被另一个事务方法调用时,应该如何进行事务控制
@Transactional
public void a(){
b();
}
@Transactional(propagation = Propagation.REQUIRED)//【默认值】需要事务,有则加入,无则创建新事务
public void b(){
}
Spring支持通过配置的形式来实现7种事务传播行为,我们需要掌握其中的前两种
属性值 | 含义 |
---|---|
REQUIRED | 【默认值】需要事务,有则加入,无则创建新事务 |
REQUIRES_NEW | 需要新事务,无论有无,总是创建新事务 |
SUPPORTS | 支持事务,有则加入,无则在无事务状态中运行 |
NOT_SUPPORTED | 不支持事务,在无事务状态下运行,如果当前存在已有事务,则挂起当前事务 |
MANDATORY | 必须有事务,否则抛异常 |
NEVER | 必须没事务,否则抛异常 |
NESTED | 如果一个活动的事务存在,则运行在一个嵌套的事务中。 |
如果没有活动事务, 则开启一个新的事务。内层事务依赖于外层事务。 | |
外层事务失败时,会回滚内层事务所做的动作。而内层事务操作失败并不会引起外层事务的回滚 |