《Spring事务管理》
目录
一、数据库事务
数据库事务( transaction)是访问并可能操作各种数据项的一个数据库操作序列,这些操作要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务由事务开始与事务结束之间执行的全部数据库操作组成。
事务特点
1、原子性(Atomicity):事务中的全部操作在数据库中是不可分割的,要么全部完成,要么全部不执行。
2、一致性(Consistency):几个并行执行的事务,其执行结果必须与按某一顺序 串行执行的结果相一致。
3、隔离性(Isolation):事务的执行不受其他事务的干扰,事务执行的中间结果对其他事务必须是透明的。
4、持久性(Durability):对于任意已提交事务,系统必须保证该事务对数据库的改变不被丢失。
二、Spring事务操作
核心注解:@Transactional
事务并发
在企业级应用中,多用户访问数据库是常见的场景,这就是所谓的事务的并发。事务并发所可能存在的问题:
- 脏读:一个事务读到另一个事务未提交的更新数据;
- 不可重复读:一个事务两次读同一行数据,可是这两次读到的数据不一样;
- 幻读:一个事务执行两次查询,但第二次查询比第一次查询多出了一些数据行;
- 丢失更新:撤消一个事务时,把其它事务已提交的更新的数据覆盖了。
通过设定相应的数据库事物隔离级别来解决事物带来的并发问题,隔离级别有5个,如下:
- DEFAULT:这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别;
- 未提交读(read uncommited):是最低的事务隔离级别,它允许另外一个事务可以看到这个事务未提交的数据,脏读,不可重复读,虚读都有可能发生;
- 已提交读(read commited):保证一个事物提交后才能被另外一个事务读取。另外一个事务不能读取该事物未提交的数据避免脏读。但是不可重复读和虚读有可能发生;
- 可重复读(repeatable read):避免脏读和不可重复读.但是虚读有可能发生;
- 串行化的(serializable):这是花费最高代价但最可靠的事务隔离级别。事务被处理为顺序执行。可以避免所有读问题。
其中,MySQL默认采用repeatable read隔离级别;Oracle默认采用read commited隔离级别,隔离级别越高,意味着数据库事务并发执行性能越差,能处理的操作就越少。
案例一
- com.hpr.mapper.StudentMapper
...
public interface StudentMapper {
...
int deleteByTeacherId(int teacherId);
}
- mappers/StudentMapper.xml
<delete id="deleteByTeacherId">
delete
from student
where teacher_id = #{teacherId}
</delete>
- com.hpr.service.ITeacherService
...
public interface ITeacherService {
...
Response<Object> testTransaction(int teacherId);
}
- com.hpr.service.impl.TeacherService
...
public class TeacherService implements ITeacherService {
...
//事务:一荣俱荣,一败俱败
@Override
@Transactional
public Response<Object> testTransaction(int teacherId) {
//数据库操作1
int count1 = teacherMapper.deleteById(teacherId);
//模拟异常
int x = 3 / 0;
//数据库操作2
int count2 = studentMapper.deleteByTeacherId(teacherId);
if (count1 > 0 && count2 > 0) {
return new Response<>(200, "success");
} else {
return new Response<>(-1, "数据删除失败!");
}
}
}
- com.hpr.controller.MybatisController
...
public class MybatisController {
...
@GetMapping("/testTransaction")
@ApiOperation("测试事务处理")
public Response<Object> testTransaction(@ApiParam("教师ID") @RequestParam int teacherId) {
return iTeacherService.testTransaction(teacherId);
}
}
- 启动测试
执行结果
当事务中发生异常,所有操作将都不会成功,数据库回滚至操作前的状态。
总结
重点
- 数据库事务概念及四大特性;
- Spring事务操作代码实现。
难点
- 事务并发带来的问题及解决方式;
- @Transactional注解的相关属性。