什么是事务?

数据库事务是指一系列紧密操作,要么全副胜利,要么全副失败。它有四种个性:原子性、一致性、隔离性和持久性

而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@AllArgsConstructorpublic 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@AllArgsConstructorpublic 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类@Overridepublic 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@Transactionalpublic 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@Transactionalpublic 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.requiredTestjava.lang.RuntimeException: 子事务异样

2、父事务异样

//BookServiceImpl类@Override@Transactionalpublic 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.requiredTestjava.lang.RuntimeException: 父事务异样

SUPPORTS(反对事务,有没有都能够)

如果以后办法存在事务,则退出事务;如果以后办法不存在事务,则以非事务形式运行。这个流传行为和不写没多大区别,当前有这需要,能够不必写@Transactional。

代码:略

NOT_SUPPORTED(不反对事务,有事务也是以非事务形式执行)

这个流传行为就是,不论咋地都传不到我身上,我就是始终以非事务形式执行。

//BookServiceImpl类@Override@Transactionalpublic 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.requiredTestjava.lang.RuntimeException: 异样

MANDATORY(必须有事务,没有就抛异样)

这个流传行为就是不论咋地我都要在事务中,如果以后办法在事务中,就退出以后事务中;如果以后办法不在事务中,就抛异样。

1、以后办法存在事务

//BookServiceImpl类@Override@Transactionalpublic 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类@Overridepublic 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("第一章"));}// 输入,无事务则抛异样调用者中事务:nullorg.springframework.transaction.IllegalTransactionStateException: No existing transaction found for transaction marked with propagation 'mandatory'

NEVER(不可能有事务,有事务就抛异样)

此传播方式就是不论咋地,谁调用我,你就不许有事务,否则我就抛异样。

1、调用者有事务

//BookServiceImpl类@Override@Transactionalpublic 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.requiredTestorg.springframework.transaction.IllegalTransactionStateException: Existing transaction found for transaction marked with propagation 'never'

2、调用者无事务

//BookServiceImpl类@Overridepublic 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异样不影响AB新建一个事务
SUPPORTS:反对B退出到A事务中B无事务
NOT_SUPPORTED:不反对挂起A事务,B以无事务形式执行B无事务
MANDATORY:强制B退出到A事务中B抛异样
NEVER:绝不B抛异样B无事务

<center>扫一扫,关注我</center>