解决Mybatis-plus的BaseMapper的selectOne查询多个会异常的问题优化
一、前言
在使用Mybatis-plus所提供的SelectOne方法时候存在一个问题,就是如果查询匹配到的数据是多个的话会报如下异常:
org.mybatis.spring.MyBatisSystemException:
nested exception is org.apache.ibatis.exceptions.TooManyResultsException:
Expected one result (or null) to be returned by selectOne(), but found: 2
其实这个并不算是错误的情况,但是在编程的时候有时我的业务会有要求即便是有重复的情况下也应该返回数据,哪怕的是默认的。其实这种业务场景并不常见。
但是如果有这种需求的小伙伴可以从下面的方式进行优化。
二、解决方案
通过使用切面进行解决AOP。
如果我们希望使用Mybatis-plus的单表操作功能,我们需要将自己Mapper层接口去继承BaseMapper,从而实现简单的单表操作。例如:
public interface RoleMapper extends BaseMapper<Role> {
}
之后我们加入以下AOP配置文件:
@Aspect
@Component
public class MybatisAspectj {
// 配置织入点
@Pointcut("execution(public * com.baomidou.mybatisplus.core.mapper.BaseMapper.selectOne(..))")
public void selectOneAspect() {
}
@Before("selectOneAspect()")
public void beforeSelect(JoinPoint point) {
Object arg = point.getArgs()[0];
if (arg instanceof AbstractWrapper) {
arg = (AbstractWrapper) arg;
((AbstractWrapper) arg).last("limit 1");
}
}
}
之后就没有问题了。
原理:
这个解决方案的原理比较简单,其实就是对SelectOne参数列表的Wrapper对面默认加上一个自定义的条件limit 1
,实现只查一条。至于加上limit 1
之后是有很多优点的,详情可以看MYSQL 查询单一数据优化
这篇博客。
测试:
我新建了一个只含Role表的数据库,去查询只有"角色"的实体。:
id | name |
---|---|
1 | 测试角色1 |
2 | 角色2 |
注意:此处环境已经加上了上述AOP配置
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class SelectOneTest {
@Autowired
private RoleMapper roleMapper;
@Test
public void selectRole() {
LambdaQueryWrapper<Role> wrapper = new LambdaQueryWrapper<Role>().like(Role::getName, "角色");
List<Role> roles = roleMapper.selectList(wrapper);
System.out.println("SelectList==查询name中有‘角色’的数据:");
System.out.println(roles);
System.out.println("SelectOne==查询name中有‘角色’的数据:");
Role role = roleMapper.selectOne(wrapper);
System.out.println(role);
}
}