spring 事务

事务的特性

1
2
3
4
markdown复制代码 - 原子性: 原子性是事务的最小执行单位,事务的原子性确保动作要么全部执行完毕,要么就都不执行
- 一致性:确保数据的一致性,一致性其实就是原子性的升华,逻辑差不多,但又不完全相同
- 隔离性:并发访问下,事务之间互不干预,每个事务的独立的
- 持久性:一个事务被提交之后,在数据库中是持久的,并不会因为数据库故障等原因丢失

spring事务管理接口

1
2
3
markdown复制代码 - PlatformTransactionManager 平台事务管理器
- TransactionDefinition 事务定义信息(传播行为、事务隔离级别、只读、超时、回滚规则)
- TransactionStatus 事务状态

PlatformTransactionManager接口介绍

spring 并不直接管理事务,而是提供多种事务管理器,具体的实现交于JTA等持久化机制所提供的平台框架去实现

spring事务管理器的接口是:org.springframework.transaction.PlatformTransactionManager,为各个平台提供事务管理器,具体的实现就需要平台自己实现,

image.png

PlatformTransactionManager提供了三个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
java复制代码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个方法以及一些关于传播行为和隔离级别的常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
ini复制代码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中有五个方法,用于来获取事务的状态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
csharp复制代码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方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
typescript复制代码@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方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
typescript复制代码@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 "执行完毕";
}

声明式事务管理

1
2
3
4
5
6
7
8
9
10
11
less复制代码@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
@Override
public void test() {
add();
try {
addException();
} catch (Exception e) {
log.error("事务回滚了");
}

}

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%