MyBatis第N+1种分页方式,全新的MyBatis分页
在MyBatis的世界里,原生的分页基于RowBounds
,虽然能达到分页的目的,但是使用起来还是不那么方便.后面开发者又添加了流式查询方式,虽然可以解决部分问题,但感觉还是不是想要的分页方式.另一方面,Java界程序员大佬给出了很多优秀的分页方案,比如Mybatis-PageHelper. 世界因不一样而精彩,今天带来一种新的分页方式.希望带给使用者一种新的API使用方式.
mybatis-nosugar
特点
- 全新的通用分页不基于传统MyBatis插件接口,所有的原本普通查询也能够得到支持
- 得益于
JDK1.8
的函数式接口,新的分页方式才得以使用.使用方式更加简单 - 如果使用NoSugar内置API,操作将更加简单
支持数据库
- MYSQL
- ORACLE
- SQLSERVER
- SQLSERVER2012
- POSTGRESQL
- DB2
- HSQL
如果数据库不在上面的列表,配置mybatis.no-sugar.sql-build.dialect-class
即可支持新的数据库类型.
通用分页Api
- NoSugar内置分页Api定义了最多支持5个参数,多于5个的可以使用类型强制转换.或者自己扩展.
- 支持原Mapper已定义的查询方法.
分页方法
Page<T> page = mapper.selectPagePX(Page<T>, mapper::原查询方法的lambda引用, 原查询方法参数列表...);
简单示例
Page<Movie> page = mapper.selectPageP2(new PageImpl<>(2, 5), mapper::findByLocationAndScoreGreaterThan, "US", 9.0);
使用方式
- 引入 Maven依赖
<dependency><groupId>com.nosugarice</groupId><artifactId>mybatis-nosugar-spring</artifactId><version>${nosugar.version}</version>
</dependency>
- 在原来
Mybatis-Spring
配置的基础上把factoryBean
替换成NoSugar中的MybatisMapperFactoryBean
@MapperScan(basePackages = {"com.xxx"}, factoryBean = MybatisMapperFactoryBean.class)
public class MyBatisConfiguration {}
- 继承接口
BaseMapper<T, ID>
public interface MovieMapper extends BaseMapper<Movie, Integer> {}
示例数据
实体类
@Table(name = "movie")
public class Movie implements Serializable {private static final long serialVersionUID = -8793166370987026047L;/** 主键 */@Id@Column(name = "id", nullable = false)@GeneratedValue(strategy = GenerationType.IDENTITY)private Integer id;/** 名称 */@Column(name = "name", nullable = false)private String name;/** 地区 */@Column(name = "location", nullable = false)private String location;/** 时长 */@Column(name = "length", nullable = false)private Integer length;/** 发行日期 */@Column(name = "release_date", nullable = false)private LocalDate releaseDate;/** 名次 */@Column(name = "ordinal", nullable = false)private Integer ordinal;/** 评分 */@Column(name = "score", nullable = false)private Double score;/** 类别 */@Column(name = "category", nullable = false)private String category;...
}
Mapper接口
public interface MovieMapper extends BaseMapper<Movie, Integer> {List<Movie> findByCategoryIsNotNull();List<Movie> findByLocation(String location);List<Movie> findByLocationAndScoreGreaterThan(String location, Double score);List<Movie> findByLocationAndScoreGreaterThanAndCategoryContains(String location, Double score, String category);}
数据库初始化SQL
DROP TABLE movie IF EXISTS;
CREATE TABLE movie
(id INTEGER GENERATED BY DEFAULT AS IDENTITY,name VARCHAR(100) NOT NULL,location VARCHAR(100) NOT NULL,length INTEGER NOT NULL,release_date DATE NOT NULL,ordinal INTEGER NOT NULL,score DOUBLE NOT NULL,category VARCHAR(20) NULL,PRIMARY KEY (id)
);INSERT INTO movie VALUES (0, '肖申克的救赎', 'US', 142, '1994-09-23', 1, 9.7, '剧情');
INSERT INTO movie VALUES (1, '霸王别姬', 'CHN', 171, '1993-07-26', 2, 9.6, '剧情');
INSERT INTO movie VALUES (2, '阿甘正传 ', 'US', 142, '1994-06-23', 3, 9.5, '剧情');
INSERT INTO movie VALUES (3, '美丽人生 ', 'IT', 116, '1997-12-20', 4, 9.6, '');
INSERT INTO movie VALUES (4, '千与千寻 ', 'JP', 125, '2001-07-20', 5, 9.4, '奇幻');
INSERT INTO movie VALUES (5, '泰坦尼克号 ', 'US', 194, '1997-12-19', 6, 9.4, '爱情');
INSERT INTO movie VALUES (6, '这个杀手不太冷', 'FR', 133, '1994-09-14', 7, 9.4, '犯罪');
INSERT INTO movie VALUES (7, '星际穿越', 'US', 169, '2014-11-12', 8, 9.4, '科幻');
INSERT INTO movie VALUES (8, '无间道', 'CHN', 101, '2003-09-05', 9, 9.3, '犯罪');
INSERT INTO movie VALUES (9, '疯狂动物城', 'US', 109, '2016-03-04', 10, 9.2, '喜剧');
INSERT INTO movie VALUES (10, '机器人总动员', 'US', 98, '2008-06-27', 11, 9.3, '动画');
INSERT INTO movie VALUES (11, '罗马假日', 'US', 118, '1953-08-20', 12, 9.1, '爱情');
INSERT INTO movie VALUES (12, '大话西游之大圣娶亲', 'CHN', 95, '1995-02-04', 13, 9.2, '剧情');
INSERT INTO movie VALUES (13, '大话西游之月光宝盒', 'CHN', 87, '1995-01-21', 14, 9.0, '喜剧');
INSERT INTO movie VALUES (14, '指环王3', 'US', 201, '2003-12-17', 15, 9.3, null);
基于0个参数的分页示例
Page<Movie> page = mapper.selectPageP0(new PageImpl<>(2, 5), mapper::findByCategoryIsNotNull);
MovieMapper.adapterCount : ==> Preparing: SELECT COUNT(*) FROM movie WHERE category IS NOT NULL
MovieMapper.adapterCount : ==> Parameters:
MovieMapper.adapterCount : <== Total: 1
MovieMapper.adapterPage : ==> Preparing: SELECT id AS "id", name AS "name", location AS "location", length AS "length", release_date AS "releaseDate", ordinal AS "ordinal", score AS "score", category AS "category" FROM movie WHERE category IS NOT NULL OFFSET 5 LIMIT 5
MovieMapper.adapterPage : ==> Parameters:
MovieMapper.adapterPage : <== Total: 5
基于三个参数的分页示例
Page<Movie> page = mapper.selectPageP3(new PageImpl<>(2, 2), mapper::findByLocationAndScoreGreaterThanAndCategoryContains, "US", 9.0, "情");
MovieMapper.adapterCount : ==> Preparing: SELECT COUNT(*) FROM movie WHERE location = ? AND score > ? AND category LIKE ?
MovieMapper.adapterCount : ==> Parameters: US(String), 9.0(Double), %情%(String)
MovieMapper.adapterCount : <== Total: 1
MovieMapper.adapterPage : ==> Preparing: SELECT id AS "id", name AS "name", location AS "location", length AS "length", release_date AS "releaseDate", ordinal AS "ordinal", score AS "score", category AS "category" FROM movie WHERE location = ? AND score > ? AND category LIKE ? OFFSET 2 LIMIT 2
MovieMapper.adapterPage : ==> Parameters: US(String), 9.0(Double), %情%(String)
MovieMapper.adapterPage : <== Total: 2
全新Count查询
基于SelectMapper#adapterCount
在原查询方法上开启Count查询.
示例
long count=mapper.countP3(mapper::findByLocationAndScoreGreaterThanAndCategoryContains, "US", 9.0, "情");
注意
调用的方法除第一个方法引用参数外其他的参数类型要和原方法对应.
全新exists查询
基于SelectMapper#adapterExists
在原查询方法上开启Exists查询.
示例
Optional<Integer> optional = mapper.existsP3(mapper::findByLocationAndScoreGreaterThanAndCategoryContains, "US", 9.0, "情");
Assertions.assertTrue(optional.isPresent());
基于NoSugar内置Api的分页方式
如果Mapper
接口继承NoSugar的内置通用Mapper
,分页将更加简单
/*** 分页查询** @param entity 实体参数* @param page 分页参数* @return 分页数据*/
default Page<T> selectPage(T entity, Page<T> page) {return selectPageX(entity, page, this::count, (tEntity, tPage) -> selectList(EntityToCriterion.getInstance().entityToSimpleCriteriaQuery(tEntity).limit(tPage)));
}/*** 分页查询** @param criteria 查询参数* @param page 分页参数* @return 分页数据*/
default <C> Page<T> selectPage(CriteriaQuery<T, C> criteria, Page<T> page) {return selectPageX(criteria, page, this::count, (tCriteriaQuery, tPage) -> selectList(tCriteriaQuery.limit(tPage)));
}
不足
分页语句的SQl优化只是简单处理,没有做过多的优化,使用者可以引入其他库解析SQL分析语义优化Count
语句.实现Dialect#optimizationCountSql
即可优化.这块因为交给使用者.
NoSugar不仅于此
- 无糖配方
- 开放大量接口给与开发者很大的自由度,让开发者根据自己的程序适配.不必千篇一律
- 性能非常丝滑,大部分功能超越动态标签,参数越多性能提升越明显
- 使用简单,不影响原有项目,无需修改原Mybatis类声明,没有重构任何Mybatis基础配置类,只需增加一个属性配置即可开启
- 无缝增强现有Mybatis项目(+功能),即使现在的项目在使用其他Mybatis框架依旧可增强
- 部分功能如分页,Count查询,JPA方式的根据方法名查询,可以单独选用
- 基础的增删改查
- 条件构造
- 插入时主键策略
- 批处理增强模式
- 全新的通用分页方式,无需插件
- 全新的通用Count查询方法
- 软删除
- 乐观锁
- 动态表名
- 更易用的值处理器
- Jpa式根据方法名查询,删除
MyBatis第N+1种分页方式,全新的MyBatis分页相关推荐
- layui table 表格两种赋值方式下,data分页效果有效, url分页效果的失效 问题的解决。
layui table 表格两种赋值方式下,data分页效果有效, url分页效果的失效 问题的解决. 参考文章: (1)layui table 表格两种赋值方式下,data分页效果有效, url分页 ...
- mybatis 一对多 两种查询方式
注意事项: 如果是多表 例如有A表,B表 A是多端,B是一端 那么就要在B端声明A端的集合 必须 上代码: 我使用的是java语言,先看实体类 这是单表的一对多 多表跟单表逻辑是一致 public ...
- mybatis plus当月数据查询_mybatis plus的3种查询方式(小结)
本文是基于springboot框架下的查询. 一:基本配置: 1.仓库依赖 alimaven aliyun maven http://maven.aliyun.com/nexus/content/gr ...
- kesioncms ajax分页,kesion CMS 新闻添加(分页分标题)和管理
点击文章系统,进入文章系统的管理界面 在左边的操作窗口,我们可以添加文章,签收文章,能方便的管理栏目,"关闭,展开"这两项功能, 如果我们的栏目比较多或者不需要快速栏目管理通道可以 ...
- mybatis 中 Example 的使用 :条件查询、排序、分页(三种分页方式 : RowBounds、PageHelpler 、limit )
前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家.点击跳转到教程. import tk.mybatis.mapper.entity.Example;import com ...
- Mybatis的5种分页方式
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapperPUBLIC "-/ ...
- MyBatis 分页方式
一. MyBatis 分页方式 分页方式:逻辑分页和物理分页. 逻辑分页: 使用 MyBatis 自带的 RowBounds 进行分页,它是一次性查询很多数据,然后在数据中再进行检索. 物理分页: 自 ...
- Mybatis分页方式及实现原理
一.mybatis的4种分页方式(物理分页.逻辑分页) 1.借助Sql语句Q进行分页(物理分页) 2.拦截器分页(物理分页)通过拦截器给sq语句末尾加Eimt语句来查询 3.借助 数组Q进行分页(逻辑 ...
- sqlserver的四种分页方式
第一种:ROW_NUMBER() OVER()方式 select * from ( select *, ROW_NUMBER() OVER(Order by ArtistId ) AS RowId f ...
- mybatis 时间_开发工具:Mybatis.Plus.插件三种方式的逆向工程
一.逆向工程简介 在Java开发中,持久层最常用的框架就是mybatis,该框架需要编写sql语句,mybatis官方提供逆向工程,可以把数据表自动生成执行所需要的基础代码,例如:mapper接口,s ...
最新文章
- python中cgi到底是什么_python cgi是什么
- UA STAT687 线性模型II 最小二乘理论3 广义最小二乘
- poj1769 线段树优化的dp
- Java工程转换为Maven工程-b
- AspNetForums中基于角色的权限控制
- 本地运行vue.js项目,如何更改调试的默认端口?
- C# 自定义常用代码段
- 7.1 pdo 宝塔面板php_运维干货分享:centos7下源码编译安装php-7.1.5(脚本)
- Elasticsearch数据库下载
- 8080端口被占用怎么解决_端口占用不会搞?两行命令就解决!
- iOS开发者联系 联系方式
- 对SIL9022/9024的配置
- ERROR: Attempting to operate on hdfs namenode as root ERROR: but there is no HDFS_NAMENODE_USER defi
- 计算机硬件参数的工具软件,电脑硬件参数修改工具
- duilib加载资源
- 算法的时间复杂度和空间复杂度-总结
- Lucas-Kanade稀疏光流法
- 深度学习21天实战caffe学习笔记《3 :准备Caffe环境》
- P3939 数颜色 (权值线段树)
- VSS2005使用技巧
热门文章
- 如何留住你的员工——员工流失分析
- 计算机itunes无法安装,Win7电脑无法安装itunes怎么办 win7安装itunes失败的解决方法...
- linux下替代windows的软件列表
- 音乐转换成16进制写进单片机的方法(音符频率和音符的播放长度时间计算)
- N2N组建虚拟局域网——筑梦之路
- 移动端怎么让图片不失真_图片怎样放大后不模糊 图片放大不失真的方法步骤...
- MAE:视觉自监督2021(原理+代码)
- AE 制作一个简单的动画
- 用selenium实现百度贴吧自动发帖
- w8ndows 秒表,关闭 Windows Search,Win8 能变快?