Call transactional methods via an injected dependency instead of directly via ‘this‘

本文介绍了在使用SonarLint扫描SpringBoot应用代码时遇到的问题,涉及@Transactional注解引发的错误。通过引入spring-boot-starter-aop依赖,启用AOP代理并修改UserInfoService中的代码,成功解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

使用SonarLint扫描代码时,报错如下

@Slf4j
@Service
@RequiredArgsConstructor
public class UserInfoService {
    private final UserMapper userMapper;

    @Transactional(readOnly = true)
    public ResponseResult getUserInfo(String username) {
        UserInfo userInfo = this.getUserInfoByUsername(username); // issue occur

        if (userInfo == null) {
            return ResponseResult.failure(StatusCode.MESSAGE, username + " does not exist, please input username again!");
        } else {
            return ResponseResult.success(userInfo);
        }
    }

    @Transactional(readOnly = true)
    public UserInfo getUserInfoByUsername(String username) {
        return userMapper.getUserByUsername(username);
    }
}

解决方案

第一步:引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
    <version>3.2.0</version>
</dependency>

第二步:enable 代理

@SpringBootApplication
@EnableAspectJAutoProxy(exposeProxy = true) // add config
public class WebSystemApplication {
    public static void main(String[] args) {
        SpringApplication.run(WebSystemApplication.class, args);
    }
}

第三步:修复问题

@Slf4j
@Service
@RequiredArgsConstructor
public class UserInfoService {
    private final UserMapper userMapper;

    @Transactional(readOnly = true)
    public ResponseResult getUserInfo(String username) {
        UserInfoService u = (UserInfoService) AopContext.currentProxy(); // use proxy
        UserInfo userInfo = u.getUserInfoByUsername(username);

        if (userInfo == null) {
            return ResponseResult.failure(StatusCode.MESSAGE, username + " does not exist, please input username again!");
        } else {
            return ResponseResult.success(userInfo);
        }
    }

    @Transactional(readOnly = true)
    public UserInfo getUserInfoByUsername(String username) {
        return userMapper.getUserByUsername(username);
    }
}

通过注入依赖而不是直接使用`this`来调用事务管理的方法是一种常见的设计模式,特别是在面向对象的编程语言中,如Java或Spring框架。这种方式的主要目的是解耦和提高代码的可测试性。 通常,当我们需要在一个服务或组件内部操作数据库并确保其操作在事务上下文中完成时,我们会创建一个拥有事务处理能力的服务层(比如DAO或Repository)。这个服务会有一个公共方法,接受作为依赖注入的事务管理器实例。然后,这个方法会在调用实际的数据访问操作之前开始事务,并在操作完成后自动提交或回滚事务,而不需要在每个具体操作处显式地管理它。 例如,在Java Spring中: ```java @Service public class UserService { @Autowired private TransactionManager transactionManager; public void createUser(User user) { try { transactionManager.getTransaction(); // 执行插入用户数据的操作 userDao.save(user); transactionManager.commitTransaction(); } catch (Exception e) { transactionManager.rollbackTransaction(); throw e; } } } ``` 这样做有几个好处: 1. **模块化**:将事务处理从具体的业务逻辑分离出来,使得代码更专注于核心功能。 2. **测试友好**:因为依赖注入可以方便地替换为模拟对象,所以可以在单元测试中隔离和控制事务行为。 3. **异常传播**:如果事务管理器抛出异常,整个事务会被回滚,避免了部分操作成功带来的脏数据状态。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值