共计 9223 个字符,预计需要花费 24 分钟才能阅读完成。
什么是事务?
数据库事务是指一系列紧密操作,要么全副胜利,要么全副失败。它有四种个性: 原子性、一致性、隔离性和持久性 。
而 spring 事务是封装在数据库事务之上的一种事务处理机制,它有两种治理形式: 编程式事务和申明式事务 。在平时应用中,咱们大多应用 @Transactional 申明式事务来治理,这也是 spring 举荐的形式,上面例子也对立采纳此种形式。
上面咱们次要来看看 spring 事务的流传机制
spring 事务的流传机制
spring 事务的流传机制有七种:REQUIRED、REQUIRES_NEW、NESTED、SUPPORTS、NOT_SUPPORTED、MANDATORY 和 NEVER。
首先要晓得事务的流传指的是一个办法调用另外一个办法并将事务传递给它,而流传机制是针对被调用者,管制它是否被流传或者被怎么流传。注: 前面屡次提到 此办法在 / 不在事务中,指的是调用者是否开启了事务 。
上面咱们来仔细分析一下这几种传播方式。
REQUIRED(有事务则退出,没有则创立)
REQUIRED 是 spring 事务的默认形式,如果以后办法不在事务中,就创立一个新的事务;如果以后办法在事务中,就退出到这个事务中。
举个例子,咱们操作 book 书籍表和 title 章节表,先插入 book 表,而后再插入 title 表( 上面几种传播方式都以这两张表为例 )。BookServiceImpl 中办法(调用者)调用 TitleServiceImpl 中办法(被调用者)。上面分两种状况:
1、调用者有事务
@Slf4j
@Service
@AllArgsConstructor
public class BookServiceImpl implements BookService {
private final BookMapper bookMapper;
private final TitleService titleService;
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
}
@Slf4j
@Service
@AllArgsConstructor
public class TitleServiceImpl implements TitleService {
private final TitleMapper titleMapper;
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
}
// 输入,被调用者应用的是调用者的事务
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
2、调用者无事务
//BookServiceImpl 类
@Override
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.REQUIRED)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,被调用者创立新事务
调用者中事务:null
被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest
REQUIRES_NEW(新事务,有事务就创立新事务)
如果以后办法存在事务,则把以后事务挂起,(这个挂起怎么了解呢?就是将现存的事务放在一边,我不必这个事务),本人新建一个事务。调用者事务和被调用者事务两不相干。
//BookServiceImpl 类
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,被调用者和调用者是两个不同事务
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest
NESTED(嵌套事务,有事务就创立子事务)
如果以后办法存在事务,则创立一个子事务,等父事务提交当前,子事务再提交;如果以后没有事务,则新建事务。(子事务异样,父事务不肯定回滚;但父事务异样,则子事务必定回滚)
1、子事务异样
//BookServiceImpl 类
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
try {
// 流传事务,捕捉异样
titleService.titleTransaction();} catch (Exception e) {e.printStackTrace();
}
}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.NESTED)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
throw new RuntimeException("子事务异样");
}
// 输入,title 表插入回滚了,然而 book 表插入未回滚
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
java.lang.RuntimeException: 子事务异样
2、父事务异样
//BookServiceImpl 类
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();
throw new RuntimeException("父事务异样");
}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.NESTED)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,book 的插入和 title 的插入都回滚了
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
java.lang.RuntimeException: 父事务异样
SUPPORTS(反对事务,有没有都能够)
如果以后办法存在事务,则退出事务;如果以后办法不存在事务,则以非事务形式运行。这个流传行为和不写没多大区别,当前有这需要,能够不必写 @Transactional。
代码:略
NOT_SUPPORTED(不反对事务,有事务也是以非事务形式执行)
这个流传行为就是,不论咋地都传不到我身上,我就是始终以非事务形式执行。
//BookServiceImpl 类
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
throw new RuntimeException("异样");
}
// 输入,尽管被调用者中有事务,也抛出异样,然而数据不会回滚
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest
java.lang.RuntimeException: 异样
MANDATORY(必须有事务,没有就抛异样)
这个流传行为就是不论咋地我都要在事务中,如果以后办法在事务中,就退出以后事务中;如果以后办法不在事务中,就抛异样。
1、以后办法存在事务
//BookServiceImpl 类
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,被调用者退出到以后事务中
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
被调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
2、以后办法不存在事务
//BookServiceImpl 类
@Override
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.MANDATORY)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,无事务则抛异样
调用者中事务:null
org.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'
NEVER(不可能有事务,有事务就抛异样)
此传播方式就是不论咋地,谁调用我,你就不许有事务,否则我就抛异样。
1、调用者有事务
//BookServiceImpl 类
@Override
@Transactional
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.NEVER)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,调用者有事务,则被调用者就抛异样
调用者中事务:com.example.demo.transaction.service.impl.BookServiceImpl.requiredTest
org.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'
2、调用者无事务
//BookServiceImpl 类
@Override
public void bookTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("调用者中事务:{}", transactionName);
bookMapper.insert(new Book().setAuthor("zpg"));
// 流传事务
titleService.titleTransaction();}
//TitleServiceImpl 类
@Override
@Transactional(propagation = Propagation.NEVER)
public void titleTransaction() {String transactionName = TransactionSynchronizationManager.getCurrentTransactionName();
log.info("被调用者中事务:{}", transactionName);
titleMapper.insert(new Title().setName("第一章"));
}
// 输入,调用者无事务,被调用者尽管有事务,然而会以无事务形式执行
调用者中事务:null
被调用者中事务:com.example.demo.transaction.service.impl.TitleServiceImpl.requiredTest
总结
接下来咱们总结一下各种传播方式下,调用者和被调用者是怎么操作事务的。注: A 办法是调用者,B 办法是被调用者。对于 A 办法来说,就两种状况:有事务和无事务,而对于 B 办法来说,有七种状况 ,上面看看每种状况下 B 办法是怎么操作事务的。
A 办法调用 B 办法,B 办法定义的事务类型 | A 办法有事务时 | A 办法无事务时 |
---|---|---|
REQUIRED:默认 | B 和 A 事务合并成一个事务 | B 新建一个事务 |
REQUIRES_NEW:必须新的 | B 新建一个事务,和 A 事务无关,互不影响 | B 新建一个事务 |
NESTED:嵌套 | B 新建一个 A 的子事务,A 异样影响 B,B 异样不影响 A | B 新建一个事务 |
SUPPORTS:反对 | B 退出到 A 事务中 | B 无事务 |
NOT_SUPPORTED:不反对 | 挂起 A 事务,B 以无事务形式执行 | B 无事务 |
MANDATORY:强制 | B 退出到 A 事务中 | B 抛异样 |
NEVER:绝不 | B 抛异样 | B 无事务 |
<center> 扫一扫,关注我 </center>