Java中@Transactional注解应放在何处?

Java中@Transactional注解应放在何处?

技术背景

在Java开发中,@Transactional 注解用于实现事务管理,确保一系列操作要么全部成功,要么全部失败。然而,关于该注解应放置在DAO类及其方法、使用DAO对象的服务类,还是同时注解这两层,开发者存在不同观点。

实现步骤

放在服务层

大多数情况下,事务应该放在服务层。服务层了解工作单元和用例,当一个服务中注入了多个需要在单个事务中协同工作的DAO时,在服务层使用 @Transactional 是合适的。例如,在一个“更改密码”的操作中,可能涉及更改密码、审计更改和发送邮件通知客户端等操作,若审计失败,密码更改也应失败,此时将事务放在服务层能确保这些操作在一个事务中完成。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Transactional
public class UserService {
@Autowired
private UserDao userDao;
@Autowired
private AuditDao auditDao;
@Autowired
private EmailService emailService;

public void changePassword(Long userId, String newPassword) {
// 更改密码
userDao.changePassword(userId, newPassword);
// 审计更改
auditDao.recordPasswordChange(userId);
// 发送邮件通知
emailService.sendPasswordChangeEmail(userId);
}
}

放在DAO层

在某些情况下,也可以在DAO层使用 @Transactional(propagation = Propagation.MANDATORY)。这有助于检测调用者忘记启动事务的错误。如果DAO方法被注解为 MANDATORY 传播,当方法被调用时没有活动事务,将抛出异常。

1
2
3
4
5
6
7
@Repository
public class UserDao {
@Transactional(propagation = Propagation.MANDATORY)
public void changePassword(Long userId, String newPassword) {
// 数据库操作
}
}

同时注解两层

若想确保DAO方法总是从具有事务的服务层调用,可以同时在服务层和DAO层注解。在DAO层使用 propagation = Propagation.MANDATORY 可以限制DAO方法不被从UI层(或控制器)调用,并且在单元测试DAO层时,也能确保对其事务功能进行测试。

最佳实践

  • 粒度控制:根据业务需求控制事务的粒度。如果业务操作涉及多个DAO操作,且需要保证原子性,应在服务层使用 @Transactional;如果单个DAO操作需要独立事务控制,可以在DAO层使用。
  • 异常处理:默认情况下,@Transactional 只对 RuntimeException 进行回滚。可以通过设置 rollbackFor = Exception.class 让其对所有异常进行回滚。
1
2
3
4
@Transactional(readOnly = false, rollbackFor = Exception.class)
public void myServiceMethod() {
// 业务逻辑
}
  • 只读事务:对于只读操作,可以设置 readOnly = true 以优化事务。
1
2
3
4
5
@Transactional(readOnly = true)
public User getUserById(Long userId) {
// 查询操作
return userDao.getUserById(userId);
}

常见问题

  • 嵌套事务问题:如果在服务层和DAO层都使用 @Transactional,可能会担心出现嵌套事务。实际上,在JPA中,若使用默认的传播行为,当进入DAO时,如果已经存在事务,会继续使用该事务,不会创建嵌套事务。但如果使用 propagation = Propagation.REQUIRES_NEW,则会创建新的事务。
  • 性能问题@Transactional 注解可能会降低方法性能,因为它涉及事务拦截器和AOP代理的执行。因此,应避免在不必要的地方使用该注解。
  • 注解位置:Spring建议将 @Transactional 注解放在具体类上,而不是接口上。

Java中@Transactional注解应放在何处?
https://119291.xyz/posts/2025-04-21.java-transactional-annotation-placement/
作者
ww
发布于
2025年4月22日
许可协议