Spring Transactional 事务
本文最后更新于 947 天前,其中的信息可能已经有所发展或是发生改变。

@Transactional

事务隔离级别 (Isolation)

@Transactional(isolation = Isolation.DEFAULT)

隔离级别说明
DEFAULT使用数据库默认的隔离级别,MySQL默认采用REPEATABLE_READ隔离级别,Oracle默认采用READ_COMMITTED隔离级别。
READ_UNCOMMITTED读未提交,一个事务可以读到另一事务未提交的数据。
READ_COMMITTED读已提交,一个事务只能读到另一事务已提交的数据,避免脏读。
REPEATABLE_READ可重复读,一个事务多次读取同一数据不受另一事务的提交影响,避免不可重复读。
SERIALIZABLE串行化,事务读写时使用表锁,避免幻读。

事务传播机制 (Propagation)

@Transactional(propagation = Propagation.REQUIRED)

传播行为说明
REQUIRED如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新事务。
SUPPORTS如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。
MANDATORY如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。
REQUIRES_NEW创建一个新事务,如果当前存在事务,则把当前事务挂起。
NOT_SUPPORTED以非事务方式运行,如果当前存在事务,则把当前事务挂起。
NEVER以非事务方式运行,如果当前存在事务,则抛出异常。
NESTED如果当前存在事务,则嵌套在事务内执行;如果当前没有事务,则创建一个新事务。

事务超时属性 (Timeout)

@Transactional(timeout = TransactionDefinition.TIMEOUT_DEFAULT)

允许事务执行的最长时间,如果超过该时间限制但事务还没有完成,就自动回滚事务。以int设置超时时间,单位是秒,默认值为-1,表示事务超时时间取决于数据库的设置或者没有超时时间。

事务只读属性 (readOnly)

@Transactional(readOnly = false)

对于只有查询没有写入的事务,可以指定事务只读属性为true,即只读事务。

此时我们不经疑问,为什么查询操作还需开启事务呢?

MySQL官网给出的答复是:

MySQL默认对每一个新建立的连接都启用了autocommit模式。在该模式下,每一个发送到MySQL服务的sql语句都会在一个单独的事务中进行处理,sql执行结束后自动提交事务。

我进一步解释下:

  1. 如果一次执行单条查询,则没必要启用只读事务,因为数据库会默认开启事务并自动提交。
  2. 如果一次执行多条查询,多条查询结果需要保持整体数据的一致性,此时就需要启用只读事务。否则前一个事务查询后,中间被其它事务修改并提交,后一个事务的查询结果将与前一个事务有出入。

事务回滚规则 (rollbackFor)

@Transactional(rollbackFor = Exception.class)

该规则定义了哪些异常会导致事务回滚。默认情况下,方法只有抛出RuntimeExceptionError异常才会回滚事务,而抛出(Checked)检查型异常时不会回滚事务。

@Transactional的作用范围

  • 方法:推荐,只能注解在public修饰的方法上,否则失效。
  • 类:如果注解在类上,表示对该类的所有public方法都生效。

手动提交事务

import org.springframework.stereotype.Service;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import javax.annotation.Resource;
@Service
public class StorageService {
    @Resource
    private PlatformTransactionManager platformTransactionManager;
    @Resource
    private StorageMapper storageMapper;
    public void add() {
        //自定义事务配置,@Transactional属性的默认配置就是出自DefaultTransactionDefinition
        DefaultTransactionDefinition defaultTransactionDefinition = new DefaultTransactionDefinition();
        //开启事务
        TransactionStatus transactionStatus = platformTransactionManager.getTransaction(defaultTransactionDefinition);
        try {
            //插入数据
            Storage storage = new Storage();
            storage.setId(1);
            storageMapper.insert(storage);
            //提交事务
            platformTransactionManager.commit(transactionStatus);
        } catch (Exception e) {
            //回滚事务
            platformTransactionManager.rollback(transactionStatus);
        }
    }
}

TransactionSynchronizationManager

AbstractPlatformTransactionManager抽象类实现了PlatformTransactionManager接口,它的getTransaction方法会初始化TransactionSynchronizationManager类,TransactionSynchronizationManager使用多个ThreadLocal维护了每个线程的事务资源。

我们可以通过实现TransactionSynchronizatio接口,并将其注册到TransactionSynchronizationManager就能完成对事务的监听。

  1. 声明事件
    import org.springframework.context.ApplicationEvent;
    
    public class AuditEvent extends ApplicationEvent {
    
        private Object source;
        public int status;
        private String message;
    
        public AuditEvent(Object source, int status, String message) {
            super(source);
            this.source = source;
            this.message = message;
        }
    
        public int getStatus() {
            return status;
        }
    
        public String getMessage() {
            return message;
        }
    }
  2. 发布事件
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.ApplicationEventPublisher;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    import org.springframework.transaction.support.TransactionSynchronizationManager;
    
    import javax.annotation.Resource;
    
    @Slf4j
    @Service
    public class StorageService {
    
        @Resource
        private StorageMapper storageMapper;
        @Resource
        private ApplicationEventPublisher eventPublisher;
    
        @Transactional
        public void add() {
            Storage storage = new Storage();
            storage.setId(1);
            storageMapper.insert(storage);
    
            log.info("service: {}", Thread.currentThread().getName());
            log.info("service: {}", TransactionSynchronizationManager.isActualTransactionActive());
            log.info("service: {}", TransactionSynchronizationManager.getCurrentTransactionName());
    
            AuditEvent auditEvent = new AuditEvent(this, 1, "审核中");
            eventPublisher.publishEvent(auditEvent);
        }
    }
  3. 监听事件
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.context.event.EventListener;
    import org.springframework.stereotype.Component;
    import org.springframework.transaction.support.TransactionSynchronization;
    import org.springframework.transaction.support.TransactionSynchronizationManager;
    
    @Slf4j
    @Component
    public class AuditEventProcessor {
    
        @EventListener(classes = AuditEvent.class)
        public void processor(AuditEvent event) {
    
            log.info("processor: {}", Thread.currentThread().getName());
            log.info("processor: {}", TransactionSynchronizationManager.isActualTransactionActive());
            log.info("processor: {}", TransactionSynchronizationManager.getCurrentTransactionName());
    
            TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() {
                @Override
                public void beforeCommit(boolean readOnly) {
                    log.info("事务提交(commit)前执行");
                }
    
                @Override
                public void beforeCompletion() {
                    log.info("事务提交(commit)后,注销(deregister)前执行");
                }
    
                @Override
                public void afterCommit() {
                    log.info("事务关闭(close)后执行");//事务先注销(deregister),后关闭(close)
                }
    
                @Override
                public void afterCompletion(int status) {
                    log.info("afterCommit后执行");
                }
            });
    
            log.info(event.getMessage());
        }
    }
如果觉得本文对您有帮助,记得收藏哦~
上一篇
下一篇