@Service
public class UserService {
@Transactional
public void createUser(User user) {
userDao.insert(user);
accountDao.insert(new Account(user.getId()));
}
}
| 属性 | 说明 | 默认值 |
|---|
| propagation | 传播行为 | REQUIRED |
| isolation | 隔离级别 | DEFAULT |
| timeout | 超时时间(秒) | -1(不超时) |
| readOnly | 是否只读 | false |
| rollbackFor | 回滚异常类型 | RuntimeException |
| noRollbackFor | 不回滚异常类型 | - |
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 30,
readOnly = false,
rollbackFor = Exception.class
)
public void updateUser(User user) {
// ...
}
| 传播行为 | 说明 |
|---|
| REQUIRED | 有事务则加入,没有则新建(默认) |
| SUPPORTS | 有事务则加入,没有则非事务执行 |
| MANDATORY | 有事务则加入,没有则抛异常 |
| REQUIRES_NEW | 新建事务,挂起当前事务 |
| NOT_SUPPORTED | 非事务执行,挂起当前事务 |
| NEVER | 非事务执行,有事务则抛异常 |
| NESTED | 有事务则嵌套执行,没有则新建 |
@Transactional
public void methodA() {
// 开启事务 A
methodB(); // 加入事务 A
}
@Transactional
public void methodB() {
// 使用事务 A
}
@Transactional
public void methodA() {
// 开启事务 A
methodB(); // 挂起事务 A,开启事务 B
// 恢复事务 A
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void methodB() {
// 使用事务 B
}
@Transactional
public void methodA() {
// 开启事务 A
try {
methodB(); // 创建保存点,嵌套事务
} catch (Exception e) {
// methodB 回滚到保存点,methodA 可以继续
}
}
@Transactional(propagation = Propagation.NESTED)
public void methodB() {
// 嵌套事务
}
| 特性 | REQUIRES_NEW | NESTED |
|---|
| 事务关系 | 独立事务 | 嵌套事务 |
| 外层回滚 | 内层不回滚 | 内层回滚 |
| 内层回滚 | 外层不回滚 | 外层可选择是否回滚 |
| 实现方式 | 新建连接 | 保存点 |
| 隔离级别 | 说明 |
|---|
| DEFAULT | 使用数据库默认隔离级别 |
| READ_UNCOMMITTED | 读未提交 |
| READ_COMMITTED | 读已提交 |
| REPEATABLE_READ | 可重复读 |
| SERIALIZABLE | 串行化 |
@Transactional(isolation = Isolation.READ_COMMITTED)
public void updateUser(User user) {
// ...
}
- RuntimeException 和 Error 回滚
- 检查异常(Exception)不回滚
// 指定回滚异常
@Transactional(rollbackFor = Exception.class)
public void method1() throws Exception {
// 所有异常都回滚
}
// 指定不回滚异常
@Transactional(noRollbackFor = BusinessException.class)
public void method2() {
// BusinessException 不回滚
}
@Transactional
public void method() {
try {
// 业务逻辑
} catch (Exception e) {
// 手动标记回滚
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
}
}
@Transactional
private void method() { // 事务失效
// ...
}
@Service
public class UserService {
public void methodA() {
methodB(); // 事务失效,直接调用不走代理
}
@Transactional
public void methodB() {
// ...
}
}
@Transactional
public void method() {
try {
// 业务逻辑
throw new RuntimeException();
} catch (Exception e) {
// 异常被捕获,事务不回滚
log.error("error", e);
}
}
@Transactional
public void method() throws Exception {
// 抛出检查异常,默认不回滚
throw new Exception();
}
// 解决方案
@Transactional(rollbackFor = Exception.class)
public void method() throws Exception {
throw new Exception();
}
MyISAM 引擎不支持事务。
// 没有 @Service 注解,不是 Spring Bean
public class UserService {
@Transactional
public void method() {
// 事务失效
}
}
@Transactional
public void method() {
new Thread(() -> {
// 新线程,不在同一个事务中
userDao.insert(user);
}).start();
}
@Service
public class UserService {
@Autowired
private TransactionTemplate transactionTemplate;
public void createUser(User user) {
transactionTemplate.execute(status -> {
try {
userDao.insert(user);
accountDao.insert(new Account(user.getId()));
return true;
} catch (Exception e) {
status.setRollbackOnly();
return false;
}
});
}
}
@Service
public class UserService {
@Autowired
private PlatformTransactionManager transactionManager;
public void createUser(User user) {
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
TransactionStatus status = transactionManager.getTransaction(def);
try {
userDao.insert(user);
accountDao.insert(new Account(user.getId()));
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
| 方案 | 说明 |
|---|
| 2PC | 两阶段提交 |
| TCC | Try-Confirm-Cancel |
| 本地消息表 | 基于消息队列 |
| Saga | 长事务拆分 |
| Seata | 阿里开源分布式事务框架 |
@GlobalTransactional
public void purchase(String userId, String commodityCode, int count) {
// 扣减库存
storageService.deduct(commodityCode, count);
// 创建订单
orderService.create(userId, commodityCode, count);
}