@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执行结束后自动提交事务。
我进一步解释下:
- 如果一次执行单条查询,则没必要启用只读事务,因为数据库会默认开启事务并自动提交。
- 如果一次执行多条查询,多条查询结果需要保持整体数据的一致性,此时就需要启用只读事务。否则前一个事务查询后,中间被其它事务修改并提交,后一个事务的查询结果将与前一个事务有出入。
事务回滚规则 (rollbackFor)
@Transactional(rollbackFor = Exception.class)
该规则定义了哪些异常会导致事务回滚。默认情况下,方法只有抛出RuntimeException或Error异常才会回滚事务,而抛出(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就能完成对事务的监听。
- 声明事件
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; } } - 发布事件
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); } } - 监听事件
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()); } }