事务的特性
- 原子性: 原子性是事务的最小执行单位,事务的原子性确保动作要么全部执行完毕,要么就都不执行
- 一致性:确保数据的一致性,一致性其实就是原子性的升华,逻辑差不多,但又不完全相同
- 隔离性:并发访问下,事务之间互不干预,每个事务的独立的
- 持久性:一个事务被提交之后,在数据库中是持久的,并不会因为数据库故障等原因丢失
spring事务管理接口
- PlatformTransactionManager 平台事务管理器
- TransactionDefinition 事务定义信息(传播行为、事务隔离级别、只读、超时、回滚规则)
- TransactionStatus 事务状态
PlatformTransactionManager接口介绍
spring 并不直接管理事务,而是提供多种事务管理器,具体的实现交于JTA等持久化机制所提供的平台框架去实现
spring事务管理器的接口是:org.springframework.transaction.PlatformTransactionManager,为各个平台提供事务管理器,具体的实现就需要平台自己实现,
PlatformTransactionManager提供了三个方法
public interface PlatformTransactionManager {
//根据传播行为返回当前活动的事务或者创建一个新的事务返回
TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
//提交目前事务的状态
void commit(TransactionStatus status) throws TransactionException;
//对执行的事务进行回滚
void rollback(TransactionStatus status) throws TransactionException;
}
TransactionDefinition介绍
TransactionDefinition中定义了事务的传播行为、隔离级别、超时、只读、回滚规则。 TransactionDefinition中有5个方法以及一些关于传播行为和隔离级别的常量
public interface TransactionDefinition {
//事务的传播行为常量
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
//事务的隔离级别
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = Connection.TRANSACTION_READ_UNCOMMITTED;
int ISOLATION_READ_COMMITTED = Connection.TRANSACTION_READ_COMMITTED;
int ISOLATION_REPEATABLE_READ = Connection.TRANSACTION_REPEATABLE_READ;
int ISOLATION_SERIALIZABLE = Connection.TRANSACTION_SERIALIZABLE;
//事务默认超时时间
int TIMEOUT_DEFAULT = -1;
//返回事务的传播行为
int getPropagationBehavior();
//事务的隔离级别
int getIsolationLevel();
//获取事务的超时时间
int getTimeout();
//事务是否只读
boolean isReadOnly();
//返回事务的名称
@Nullable
String getName();
}
TransactionStatus介绍
TransactionStatus中有五个方法,用于来获取事务的状态
public interface TransactionStatus extends SavepointManager, Flushable {
//是否是一个新的事务
boolean isNewTransaction();
//是否有恢复点
boolean hasSavepoint();
//设置为只回滚
void setRollbackOnly();
//是否为只回滚
boolean isRollbackOnly();
//是否已完成
boolean isCompleted();
}
事务的传播行为
事务的传播行为是为了解决业务层之间互相调用的事务问题,当事务方法被另一个事务方法调用时,是在现有的事务中运行,还是创建一个新的事务来运行,在TransactionDefinition中定义了7个传播行为的常量
支持当前事务
- PROPAGATION_REQUIRED :如果当前存在事务,则加入该事务,如果不存在事务,则创建一个新的事务运行。
- PROPAGATION_SUPPORTS :如果当前存在事务,则加入该事务,如果不存在事务,则以非事务的方式运行。
- PROPAGATION_MANDATORY :如果当前存在事务,则加入该事务,如果不存在事务,则抛出异常。(MANDATORY:强制性)
不支持当前事务
- PROPAGATION_REQUIRES_NEW :创建一个新的事务运行,如果当前存在事务的话,则将当前事务挂起。
- PROPAGATION_NOT_SUPPORTED :以非事务的方式运行,如果当前存在事务的话,则将当前事务挂起。
- PROPAGATION_NEVER :以非事务的方式运行,如果当前存在事务的话,则抛出异常
其他情况
- PROPAGATION_NESTED :如果当前存在事务的话,则创建一个嵌套事务来运行,可以理解为子事务,多个子事务之间互不影响,外部事务回滚子事务不会回滚,子事务回滚外部事务也会回滚,子事务不可以单独提交,他依赖于外部事务,只有通过外部事务的提交,才可以提交子事务
事务的隔离级别
事务的的隔离级别定义了再并发访问下受其他事务所影响的程度,先让我们来看看并发事务下会出现哪些问题
- 脏读: 当一个事务获取数据并修改了数据,但还未提交到数据库中,此时另一个事务获取到了数据, 然后使用了该数据,因为这个数据是还未提交到数据库中,因此第二个事务读取到的数据就是"脏数据",基于脏数据的操作结果可能是不正确的
- 丢失修改: 一个事务在获取数据时,另一个事务也获取了该数据,第一个事务修改了数据并提交到数据库中,另一个事务也修改了数据并提交到数据库中,此时第二个事务修改的数据会覆盖第一个事务修改的数据,造成第一个事务的修改丢失
- 不可重复读: 当一个事务多次读取数据时,在此事务还没有结束时,另一个事务在此事务两次读取数据之间获取了该数据并进行了修改,此时此数据前后读取到的数据时不一致的,因此成为不可重复读
- 幻读: 幻读和不可重复读类似,在事务一读取多条数据时,此时事务二向数据库中插入了新数据,在事务一后面的查阅中会多出一些原本不存在的数据,就好像出现幻觉一样,一次称为幻读
不可重复读和幻读的区别 不可重复读的重点在于修改,幻读的重点在于新增或者删除
例1: 当事务1中的A用户去读取的自己的工资为1000的操作还没有完成时,事务2中的B用户将A用户的工资改为2000,导致A在读取自己的工资为2000,这就称为不可重复读
例2:在事务1中去查询工资大于2000的员工,第一次查询为只有4人,此时事务二新增一条工资大于2000的员工数据,此时事务1再次读取数据变成了5条,这称为幻读
spring 事务隔离级别
- ISOLATION_DEFAULT: 使用数据库自带的默认隔离级别,mysql默认采用的 REPEATABLE_READ隔离级别 Oracle 默认采用的 READ_COMMITTED隔离级别
- ISOLATION_READ_UNCOMMITTED: 最低的隔离级别,允许读取未提交的数据变更,可能会产生脏读、不可重复读、幻读等问题
- ISOLATION_READ_COMMITTED: 只允许读取已提交的数据,可以阻止脏读,可能会产生不可重复读、幻读等问题
- ISOLATION_REPEATABLE_READ: 对多次读取的结果必须一致,除非时同一个事务所修改的,可以阻止脏读、不可重复读,可能会产生幻读等问题
- ISOLATION_SERIALIZABLE: 最高隔离级别,每个事务必须逐个执行,根本不可能产生脏读、丢失修改、不可重复读、幻读等问题,但是严重影响了程序性能,实际开发中基本不用这个隔离级别
事务超时属性
事务超时属性定义了事务最大的执行时长,超过执行时长事务会自动回滚,其单位为秒
事务只读属性
事务只读属性标记着对事务性资源只读操作或读写操作,所谓的事务性资源就是数据源、JMS资源以及自定义的事务性资源,如果确定对事务性资源只读操作,那么可以将事务只读属性标记为true,以提高事务处理性能
回滚规则
回滚规则定义了哪些异常会回滚,哪些异常不会回滚,默认情况下只有运行时异常才会回滚,我们可以自定义那些异常回滚,也可以自定义哪些异常不回滚
spring 支持两种方式的事务管理
-
编程式事务管理
编程式事务管理在实际开发中,几乎不会用到,大多数情况下我们通过注解式事务管理,我们可以使用TransactionTemplate和PlatformTransactionManager来手动管理事务 TransactionTemplate方式
@Resource
private TransactionTemplate transactionTemplate;
@PostMapping("test1")
public Object test1() {
transactionTemplate.execute(new TransactionCallbackWithoutResult() {
@Override
protected void doInTransactionWithoutResult(TransactionStatus status) {
try {
userService.addException(); //业务代码
} catch (Exception e) {
status.setRollbackOnly(); //回滚
}
}
});
return "执行完毕";
}
PlatformTransactionManager方式
@Resource
private PlatformTransactionManager transactionManager;
@PostMapping("test2")
public Object test2() {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
userService.addException();
transactionManager.commit(status); //手动提交事务
} catch (Exception e) {
transactionManager.rollback(status); //回滚事务
}
return "执行完毕";
}
声明式事务管理
@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
@Override
public void test() {
add();
try {
addException();
} catch (Exception e) {
log.error("事务回滚了");
}
}