一、什么是事务?
事务是一组操作的集合,它是一个不可分割的工作单位。事务会把所有的操作作为一个整体,一起向数据库提交或者是撤销操作请求。所以这组操作要么同时成功,要么同时失败。
事务的操作主要有三步:
-
开启事务(一组操作开始前,开启事务):start transaction / begin ;
-
提交事务(这组操作全部成功后,提交事务):commit ;
-
回滚事务(中间任何一个操作出现异常,回滚事务):rollback ;
二、案例
1.1 需求分析
需求:当部门解散了不仅需要把部门信息删除了,还需要把该部门下的员工数据也删除了。
步骤:
-
根据ID删除部门数据
-
根据部门ID删除该部门下的员工
1.2 实现代码
DeptServiceImpl类代码如下:
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Autowired
private EmpMapper empMapper;
//根据部门id,删除部门信息及部门下的所有员工
@Override
public void delete(Integer id){
//根据部门id删除部门信息
deptMapper.deleteById(id);
//删除部门下的所有员工信息
empMapper.deleteByDeptId(id);
}
}
DeptMapper类代码如下:
@Mapper
public interface DeptMapper {
/**
* 根据id删除部门信息
* @param id 部门id
*/
@Delete("delete from dept where id = #{id}")
void deleteById(Integer id);
}
EmpMapper类代码如下:
@Mapper
public interface EmpMapper {
//根据部门id删除部门下所有员工
@Delete("delete from emp where dept_id=#{deptId}")
public int deleteByDeptId(Integer deptId);
}
正常情况下,数据库中dept表和emp表中部门及员工数据会被删除。
在DeptServiceImpl类的delete方法中代码,添加可能出现异常的代码:
@Override
public void delete(Integer id){
//根据部门id删除部门信息
deptMapper.deleteById(id);
//模拟:异常发生
int i = 1/0;
//删除部门下的所有员工信息
empMapper.deleteByDeptId(id);
}
重新运行程序:
以上程序出现的问题:即使程序运行抛出了异常,部门依然删除了,但是部门下的员工却没有删除,造成了数据的不一致。
1.3 原因分析
-
先执行根据id删除部门的操作,执行完毕后,数据库表 dept 中的数据就已经删除了。
-
执行 1/0 操作,抛出异常
-
抛出异常之前,下面所有的代码都不会执行了,根据部门ID删除该部门下的员工,这个操作也不会执行 。
此时就出现问题了,部门删除了,部门下的员工还在,业务操作前后数据不一致。
而要想保证操作前后,数据的一致性,就需要让解散部门中涉及到的两个业务操作,要么全部成功,要么全部失败 。 那我们如何让这两个操作要么全部成功,要么全部失败呢 ?
那就可以通过事务来实现,因为一个事务中的多个业务操作,要么全部成功,要么全部失败。
此时,我们就需要在delete删除业务功能中添加事务。
1.4 @Transactional注解
- 作用:就是在当前这个方法执行开始之前来开启事务,方法执行完毕之后提交事务。如果在这个方法执行的过程当中出现了异常,就会进行事务的回滚操作。
- @Transactional注解:我们一般会在业务层当中来控制事务,因为在业务层当中,一个业务功能可能会包含多个数据访问的操作。在业务层来控制事务,我们就可以将多个数据访问操作控制在一个事务范围内。
-
@Transactional注解标记在方法上:当前方法交给spring进行事务管理
在业务方法delete上加上 @Transactional 来控制事务 。
@Service
public class DeptServiceImpl implements DeptService {
@Autowired
private DeptMapper deptMapper;
@Autowired
private EmpMapper empMapper;
@Override
@Transactional //当前方法添加了事务管理
public void delete(Integer id){
//根据部门id删除部门信息
deptMapper.deleteById(id);
//模拟:异常发生
int i = 1/0;
//删除部门下的所有员工信息
empMapper.deleteByDeptId(id);
}
}
在application.yml配置文件中开启事务管理日志,就可以在控制看到和事务相关的日志信息
#spring事务管理日志
logging:
level:
org.springframework.jdbc.support.JdbcTransactionManager: debug
添加Spring事务管理后,由于服务端程序引发了异常,所以事务进行回滚。