在 Spring Boot 中,@Transactional
是用于声明式事务管理的关键注解。它基于 Spring 的 AOP(面向切面编程)实现,可以简化数据库事务的管理。
spring-boot-starter-data-jpa
或 spring-boot-starter-jdbc
DataSourceTransactionManager
),无需手动启用。@Service
public class UserService {
@Autowired
private UserRepository userRepository;
@Transactional
public void createUser(User user) {
userRepository.save(user);
// 其他数据库操作
}
}
@Service
@Transactional
public class UserService {
// 类中所有 public 方法都会应用事务
}
控制事务的边界,默认为 Propagation.REQUIRED
。
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void updateUser(User user) {
// 始终开启新事务
}
常见选项:
REQUIRED
(默认):如果当前存在事务,则加入;否则新建REQUIRES_NEW
:始终新建事务,挂起当前事务(如有)SUPPORTS
:如果当前存在事务,则加入;否则非事务运行NOT_SUPPORTED
:非事务运行,挂起当前事务(如有)MANDATORY
:必须在事务中调用,否则抛出异常NEVER
:必须在非事务中调用,否则抛出异常控制事务的隔离性,默认为 Isolation.DEFAULT
(使用数据库默认)。
@Transactional(isolation = Isolation.SERIALIZABLE)
public void sensitiveOperation() {
// 最高隔离级别
}
事务超时时间(秒),默认-1(使用数据库默认)。
@Transactional(timeout = 30)
public void longRunningProcess() {
// 超过30秒将回滚
}
优化只读操作,默认为 false
。
@Transactional(readOnly = true)
public List<User> findAllUsers() {
return userRepository.findAll();
}
指定触发回滚的异常类型:
@Transactional(rollbackFor = CustomException.class)
public void process() throws CustomException {
// 抛出 CustomException 时回滚
}
public
:由于 Spring AOP 的实现机制,非 public 方法上的 @Transactional
无效// 错误示例
public void methodA() {
methodB(); // 事务不生效
}
@Transactional
public void methodB() { ... }
RuntimeException
或 Error
// 处理检查型异常
@Transactional(rollbackFor = IOException.class)
public void fileOperation() throws IOException {
// ...
}
需配置多个事务管理器,并通过 @Transactional(value = "specificTransactionManager")
指定
logging.level.org.springframework.transaction.interceptor=TRACE
logging.level.org.springframework.jdbc.datasource.DataSourceTransactionManager=DEBUG
System.out.println(userService.getClass().getName());
// 输出应为代理类:com.sun.proxy.$ProxyXX 或 ...$$EnhancerBySpringCGLIB$$...
rollbackFor
而非依赖默认行为@Transactional
public void updateUserEmail(Long userId, String email) {
User user = userRepository.findById(userId).orElseThrow();
user.setEmail(email); // 自动脏检查,事务提交时更新
}
@Service
public class OrderService {
@Autowired
private OrderRepository orderRepository;
@Autowired
private InventoryService inventoryService;
@Transactional(
propagation = Propagation.REQUIRED,
isolation = Isolation.READ_COMMITTED,
timeout = 30,
rollbackFor = {InsufficientStockException.class, PaymentFailedException.class}
)
public void placeOrder(Order order) {
inventoryService.reduceStock(order.getItems()); // 可能抛出 InsufficientStockException
orderRepository.save(order);
processPayment(order); // 可能抛出 PaymentFailedException
}
private void processPayment(Order order) {
// 支付逻辑
}
}
@Transactional
的使用与数据库层有直接关系,但它的事务管理机制是基于数据库事务的。如果 Service 层方法使用了 Elasticsearch 客户端读写 Elasticsearch,那么 @Transactional
的行为会受到影响。
@Transactional
的适用范围@Transactional
是 Spring 提供的事务管理机制,主要用于管理数据库事务。它依赖于底层的事务管理器(如 DataSourceTransactionManager
),而这些事务管理器通常是与关系型数据库(如 MySQL、PostgreSQL)交互的。
@Transactional
可以确保数据库操作的原子性、一致性、隔离性和持久性(ACID)。@Transactional
无法直接管理其事务。@Transactional
的关系Elasticsearch 是一个分布式搜索引擎,它本身不支持传统意义上的事务(ACID)。因此,@Transactional
对 Elasticsearch 的操作没有直接的事务管理能力。
假设我们的 Service 方法同时操作了数据库和 Elasticsearch:
@Service
public class UserService {
@Autowired
private UserRepository userRepository; // 数据库操作
@Autowired
private ElasticsearchClient elasticsearchClient; // Elasticsearch 操作
@Transactional
public void createUser(User user) {
// 操作数据库
userRepository.save(user);
// 操作 Elasticsearch
IndexRequest request = new IndexRequest("users")
.id(user.getId().toString())
.source("name", user.getName(), "email", user.getEmail());
elasticsearchClient.index(request, RequestOptions.DEFAULT);
}
}
userRepository.save(user)
成功,但后续 Elasticsearch 操作失败,数据库事务会回滚(因为 @Transactional
生效),但 Elasticsearch 的数据已经写入,无法回滚。由于 Elasticsearch 不支持事务,因此需要采用其他机制来保证数据一致性。
@Transactional
public void createUser(User user) {
try {
userRepository.save(user); // 数据库操作
IndexRequest request = new IndexRequest("users")
.id(user.getId().toString())
.source("name", user.getName(), "email", user.getEmail());
elasticsearchClient.index(request, RequestOptions.DEFAULT); // Elasticsearch 操作
} catch (Exception e) {
// Elasticsearch 操作失败,手动回滚数据库
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw e;
}
}
总结
@Transactional
只对数据库事务有效:它无法管理 Elasticsearch 等非关系型数据存储的事务。如果你有更多具体的业务场景,可以进一步讨论如何设计解决方案!