文章目录
- 1. 描述
- 1.1 MybatisPlusInterceptor
- 1.2 InnerInterceptor
- 2. 实现
- 2.1 不带条件的分页查询
- 2.2 带条件的分页查询
- 2.3 简述Page类
- 3. 注意事项
1. 描述
1.1 MybatisPlusInterceptor
我们在开发的过程中,经常会遇到分页操作,其分为逻辑分页和物理分页,具体可参考我的博文:逻辑分页和物理分页
如果你用的是Mybatis-Plus
框架,可用MybatisPlusInterceptor
按如下配置分页代码:
/**
* @author 念兮为美
* @datetime 2022/11/28 14:10
* @desc mybatis plus 配置类
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 设置为使用 MYSQL 方言
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
如果你用的是低版本
的spring boot
,可用PaginationInterceptor
按如下配置:
/**
* @author 念兮为美
* @datetime 2022/11/27 15:22
* @desc mybatis plus 配置类
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public PaginationInterceptor paginationInterceptor() {
return new PaginationInterceptor();
}
}
MybatisPlusInterceptor
插件是核心插件,目前代理了Executor#query、Executor#update、StatementHandler#prepare
方法,其属性:
private List<InnerInterceptor> interceptors = new ArrayList<>();
1.2 InnerInterceptor
注意List<InnerInterceptor>
泛型中的InnerInterceptor
,mybatis-plus
提供的插件都将基于此接口来实现功能,目前已有的功能如下:
-
自动分页:
PaginationInnerInterceptor
-
多租户:
TenantLineInnerInterceptor
-
动态表名:
DynamicTableNameInnerInterceptor
-
乐观锁:
OptimisticLockerInnerInterceptor
-
sql性能规范:
IllegalSQLInnerInterceptor
-
防止全表更新与删除:
BlockAttackInnerInterceptor
【注意】使用多个功能需要注意顺序关系,建议使用如下顺序:
-
多租户
-
动态表名
-
分页,乐观锁
-
sql
性能规范,防止全表更新与删除
总结:对sql
进行单次改造的优先放入,不对sql
进行改造的最后放入。
2. 实现
2.1 不带条件的分页查询
- 编写查询展示类
/**
* @author 念兮为美
* @datetime 2023/2/2 09:58
* @desc 用户查询结果
*/
@NoArgsConstructor
@Data
@ApiModel(description = "用户返回结果")
public class UserPageVo {
@ApiModelProperty(name = "username", value = "用户名")
private String username;
@ApiModelProperty(name = "nickname", value = "昵称")
private String nickname;
@ApiModelProperty(name = "userType", value = "用户类型")
private String userType;
}
- 编写
mapper
类
@Mapper
public interface UserMapper extends BaseMapper<User> {
@Select("select " +
"username,nickname,user_type as userType " +
"from " +
"user " +
"order by " +
"create_time desc"
)
List<UserPageVo> findPageUsers(Page<UserPageVo> page);
}
- 编写
service
类
@Service
public class UserService extends ServiceImpl<UserMapper, User> {
@Resource private UserMapper userMapper;
public Page<UserPageVo> findPageUsers() {
Long currentPage = 4L;
Long pageSize = 3L;
Page<UserPageVo> page = new Page<>(currentPage, pageSize);
List<UserPageVo> pageUsers = userMapper.findPageUsers(page);
page.setRecords(pageUsers);
return page;
}
}
- 编写
controller
类
@Api(tags = "用户模块")
@RestController
@RequestMapping("/user")
@Slf4j
@Validated
public class UserController {
@Autowired private UserService userService;
@ApiOperationSupport(author = "念兮为美")
@ApiOperation(value = "用户查询接口")
@GetMapping("/findPageUsers")
public Page<UserPageVo> findPageUsers() {
return userService.findPageUsers();
}
}
- 测试运行结果
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@2ce7d43] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM user
==> Parameters:
<== Columns: total
<== Row: 24
<== Total: 1
==> Preparing: select username,nickname,user_type as userType from user order by create_time desc LIMIT ?,?
==> Parameters: 9(Long), 3(Long)
<== Columns: username, nickname, userType
<== Row: cs, null, admin
<== Row: lin, null, admin
<== Row: test3, null, TEST4
<== Total: 3
2.2 带条件的分页查询
public class UserService extends ServiceImpl<UserMapper, User> {
@Resource private UserMapper userMapper;
public Page<User> findPageUsers() {
Long currentPage = 1L;
Long pageSize = 3L;
Page<User> page = new Page<>(currentPage, pageSize);
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", "test5");
Page<User> userPage = userMapper.selectPage(page, queryWrapper);
return userPage;
}
运行结果:
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@475454ae] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM user WHERE deleted = false AND (username = ?)
==> Parameters: test2(String)
<== Columns: total
<== Row: 1
<== Total: 1
==> Preparing: SELECT username,nickname,user_type FROM user WHERE deleted=false AND (username = ?) LIMIT ?
==> Parameters: test2(String), 3(Long)
<== Columns: username, nickname, user_type
<== Row: test2, null,TEST6
<== Total: 1
2.3 简述Page类
简单分页模型, 有如下几个主要属性
/**
* 查询数据列表
*/
protected List<T> records = Collections.emptyList();
/**
* 总数
*/
protected long total = 0;
/**
* 每页显示条数,默认 10
*/
protected long size = 10;
/**
* 当前页
*/
protected long current = 1;
3. 注意事项
在编写mapper.xml
中的SQL
语句时,或者使用@select
注解编写SQL
语句时,语句末尾不能使用 ;
结尾,原因是在做分页的时候会在编写的SQL
语句后面拼接上limit
语句, 导致出现SQL
语法错误(SQLSyntaxErrorException
),如下所示:
@Select("select " +
"username,nickname,user_type as userType " +
"from " +
"user " +
"order by " +
"create_time desc;"
)
List<UserPageVo> findPageUsers(Page<UserPageVo> page);
运行结果:
JDBC Connection [com.alibaba.druid.proxy.jdbc.ConnectionProxyImpl@498d7c57] will not be managed by Spring
==> Preparing: SELECT COUNT(*) AS total FROM user
==> Parameters:
<== Columns: total
<== Row: 24
<== Total: 1
==> Preparing: select username,nickname,user_type as userType from user order by create_time desc; LIMIT ?,?
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@6f5c4fa1]
org.springframework.jdbc.UncategorizedSQLException:
### Error querying database. Cause: java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 89, line 1, column 85, token LIMIT : select username,nickname,user_type as userType from user order by create_time desc; LIMIT ?,?
### The error may exist in com/cloud/lowcode/mapper/UserMapper.java (best guess)
### The error may involve com.cloud.lowcode.mapper.UserMapper.findPageUsers
### The error occurred while executing a query
### SQL: select username,nickname,user_type as userType from user order by create_time desc; LIMIT ?,?
### Cause: java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 89, line 1, column 85, token LIMIT : select username,nickname,user_type as userType from user order by create_time desc; LIMIT ?,?
; uncategorized SQLException; SQL state [null]; error code [0]; sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 89, line 1, column 85, token LIMIT : select username,nickname,user_type as userType from user order by create_time desc; LIMIT ?,?; nested exception is java.sql.SQLException: sql injection violation, dbType mysql, , druid-version 1.2.11, syntax error: not supported.pos 89, line 1, column 85, token LIMIT : select username,nickname,user_type as userType from user order by create_time desc; LIMIT ?,?
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:92)