当前位置:首页 > 时尚生活

分页控件 Mybatis插件原理和PageHelper结合实战分页插件(七)

过往精彩文章:

Mybatis源代码分析的SqlSessionFactory(一)

Mybatis源代码分析的任务和执行程序(2)

Mybatis源代码分析的映射器SQL执行过程(3)

Mybatis源代码分析中缓存一级缓存的原理(4)

Mybatis源代码分析中缓存二级缓存的原理(5)

将米巴蒂斯与redis联合对抗L2秘藏(六)

今天给大家分享一个PageHelper,mybatis的分页插件。在解释PageHelper之前,我们需要了解mybatis的插件原理。分页

官方网站:https://github.com/pagehelper/Mybatis-PageHelper

一、插件接口

Mybatis定义了一个插件接口org。阿帕奇。伊巴蒂斯。插件。拦截器。任何自定义插件都需要实现这个接口,PageHelper实现了接口的改变

package org . Apache . ibatis . plugin;

导入Java . util . properties;

/**

* @作者克林顿Begin

*/

公共接口拦截器{

对象拦截(调用调用)抛出可抛出;

对象插件(对象目标);

无效设置属性(属性属性);

}

1:拦截拦截器,会直接覆盖你拦截对象的真实方法。

2.这是一个生成动态代理对象的方法

3:设置属性它允许您在使用插件时设置参数值。

看com。github。pagehelper。pagehelper的分页实现

/**

* Mybatis拦截器方法

*

* @param调用拦截器输入

* @return返回执行结果

* @ Throwable抛出异常

*/

公共对象拦截(调用调用)引发可投掷{

if (autoRuntimeDialect) {

SqlUtil sqlUtil = getSqlUtil(调用);

返回sqlUtil.processPage(调用);

if(自动启用){

initSqlUtil(调用);

}

返回sqlUtil.processPage(调用);

}

}

这个方法获取分页核心代码并重构BoundSql对象,这将在下面详细分析

/**

*仅阻止执行者

*

* @param目标

* @返回

*/

公共对象插件(对象目标){

Executor的目标实例){

return Plugin.wrap(target,this);

返回目标;

}

}

这个方法是截取执行器

/**

*设置属性值

*

* @param p属性值

*/

public void set Properties(Properties p){

checkVersion

//如果有多个数据源,获取jdbcurl后是否关闭数据源

string CloseConn = p . GetProperty(" CloseConn ");

//求解#97

if(stringutil . isnotempty(CloseConn)){

this . closeConn = boolean . parse boolean(closeConn);

}

//初始化SqL的PARAMS

SqL . SetParAms(p . GetProperty(" params ");

//数据库方言

字符串方言= p.getProperty("方言");

string RuntimeVaLue = p . GetProperty(" AutoRuntimeDilect ");

if(StrIngutil . iSNotempty(RuntimeFality))& amp;& amp运行时方言. equalsignorecase(" TRUE "){

this . AutoRuntimediaSelect = true;

this.autoDialect = false

this . properties = p;

} else if (StringUtil.isEmpty(方言)){

自动学习=真;

this . properties = p;

自动学习=假;

sqlUtil =新sqlUtil(方言);

SqL . SetPropertieS(p);

}

}

基本属性设置

二、插件初始化

初始化和所有mybatis初始化一样。在上一篇文章中,已经分析了Mybatis源代码分析的SqlSessionFactory (I)

私有void pluginElement(XNode父级)引发异常{

if (parent!= ) {

for (XNode子项:parent.getChildren) {

string interceptor = child . GetStringAttribute(" interceptor ");

properties properties = child . getchildrenaspproperties;

拦截器拦截器=(拦截器)解析器类(拦截器)。newInstance

interceptionrinsitivity . set properties(properties);

configuration.a ddInterceptor(拦截器状态);

}

}

}

这里说的是多个实例化的插件对象放入配置,addInterceptor最后存储在一个列表中,以为这样可以同时存储多个插件

第三,外挂拦截

该插件可以拦截mybatis的四个主要对象:ParameterHandler、ResultSetHandler、StatementHandler和Executor。源代码如下

您可以在配置类中找到它

PageHelper使用Executor进行拦截,这在上面的源代码中已经可以看到。

让我看看上图中的newExecutor方法

Executor =(Executor)interceptor chain . pluginal(Executor);

这是为了生成一个代理对象,并在生成代理对象时运行调用方法

四.插件操作

Mybatis自带Plugin方法,源代码如下

公共类插件实现InvocationHandler {

私有对象目标;

私人截击机;

私人地图& lt类别<。?>。,Set & lt方法>。>。signatureMap

私有插件(对象目标,拦截器拦截器,映射& lt类别<。?>。,Set & lt方法>。>。signatureMap) {

this.target = target

this.interceptor = interceptor

this . signatureMap = signatureMap;

}

公共静态对象包装(对象目标,拦截器){

地图<。类别<。?>。,Set & lt方法>。>。signatureMap = getSignatureMap(拦截器);

类别<。?>。type = target.getClass

类别<。?>。interfaces = getAllInterfaces(类型,signatureMap);

if(interfaces . length & gt;0) {

return Proxy.newProxyInstance(

type.getClassLoader,

界面,

新插件(目标、拦截器、签名映射);

}

返回目标;

}

公共对象调用(对象代理、方法方法、对象[]参数)引发可投掷{

Set<。方法>。methods = signaturemap . get(method . getdeclaringclass);

if (methods!= & amp& ampmethods.contains(method)) {

return interceptor . intercept(new Invocation(target,method,args));

}

return method.invoke(target,args);

throw ExceptionTil . Unwrapthrowable(e);

}

}

私有静态地图& lt类别<。?>。,Set & lt方法>。>。getSignatureMap(拦截器拦截器){

intercepts intercepts sannotation = interceptor . GetClass . GetAnnotation(intercepts . Class);

//第251期

if (interceptsAnnotation == ) {

抛出新的PluginException("在interceptor中找不到@Intercepts注释"+interceptor . getclass . getname);

}

sigs = interceptSannotation . value;

地图<。类别<。?>。,Set & lt方法>。>。signatureMap = new HashMap & lt类别<。?>。,Set & lt方法>。>。;

for(签名:sigs) {

Set<。方法>。methods = SignatureMap . get(SIG . type);

if (methods == ) {

methods = new HashSet & lt方法>。;

signatureMap.put(sig.type,methods);

}

尝试{

method method = SIG . type . GetMethod(SIG . method,SIG . args);

methods . a DD(method);

} catch(NoSuchMethodException e){

抛出新的插件异常(“在名为“+ sig.method +”的“+ sig.type +”上找不到方法”。起因:“+ e,e);

}

}

返回签名映射;

}

私有静态类& lt?>。getAllInterfaces(Class & lt;?>。类型,地图& lt类别<。?>。,Set & lt方法>。>。signatureMap) {

Set<。类别<。?>。>。interfaces = new HashSet & lt类别<。?>。>。;

while(键入!= ) {

for(Class & lt;?>。c : type.getInterfaces) {

if(signaturemap . Contains KeY(c)){

interfaces . a DD(c);

}

}

type = type.getSuperclass

}

返回接口到数组(新类& lt?>。[interfaces . size]);

}

}

wrap方法是生成一个动态代理类。

Invoke方法是一种代理绑定方法,它首先确定签名类和方法是否存在,如果不存在,则直接反映分派被拦截对象的方法;如果它们存在,调度插件的拦截器方法,然后初始化一个调用对象

让我们具体看看PageHelper。当它被执行调用时,程序将跳转到页面帮助器

公共对象拦截(调用调用)引发可投掷{

if (autoRuntimeDialect) {

SqlUtil sqlUtil = getSqlUtil(调用);

返回sqlUtil.processPage(调用);

if(自动启用){

initSqlUtil(调用);

}

返回sqlUtil.processPage(调用);

}

}

我们正在研究sqlUtil.processPage方法

/**

* Mybatis拦截器方法,这一步是嵌套的,以便在出现异常时清除空Threadlocal。

*

* @param调用拦截器输入

* @return返回执行结果

* @ Throwable抛出异常

*/

公共对象进程页(调用调用)抛出可抛出的{

对象结果= _processPage(调用);

返回结果;

clearLocalPage

}

}

继续跟进

/**

* Mybatis拦截器方法

*

* @param调用拦截器输入

* @return返回执行结果

* @ Throwable抛出异常

*/

私有对象_进程页面(调用调用)抛出可抛出的{

Object final args = invoke . GetArgs;

page page =;

//当支持方法参数时,尝试首先获取Page

if (supportMethodsArguments) {

page = GetPage(args);

}

//分页信息

行边界行边界=(行边界)参数[2];

//当支持方法参数时,如果page ==,表示没有分页条件,不需要分页查询。

if((supportMethodsArguments & amp;& amppage ==)

//当不支持分页参数时,判断LocalPage和RowBounds,判断是否需要分页。

|| (!supportMethodsArguments & amp& ampSqlUtil.getLocalPage = = & amp& amprowBounds == RowBounds。DEFAULT){

返回调用。继续;

//不支持分页参数时,page==,这里需要获取

if(!supportMethodsArguments & amp& amppage == ) {

page = GetPage(args);

}

返回doProcessPage(调用、页面、参数);

}

}

这些只是打包页面的方法,真正的核心是doProcessPage

/**

* Mybatis拦截器方法

*

* @param调用拦截器输入

* @return返回执行结果

* @ Throwable抛出异常

*/

私有页面进程页面(调用调用,页面页面,对象[]参数)抛出可抛出{

//保存行边界状态

行边界行边界=(行边界)参数[2];

//获取原ms

Mapped statement ms =(Mapped statement)参数[0];

//确定并作为页面资源进行处理

if(!isPageSqlSource(ms)) {

processMappedStatement

}

//设置当前解析器,每次使用前都会设置,ThreadLocal的值不会有不良影响

((PageSqlSource)ms.getSqlSource)。setParser(解析器);

//忽略row bounds——否则会在Mybatis中进行内存分页

args[2] = RowBounds。DEFAULT

//如果只做排序或页面大小零判断,

if (isQueryOnly(page)) {

返回doQueryOnly(页面,调用);

}

//简单的根据total的值来判断是否查询count

if (page.isCount) {

page.setCountSignal(布尔值。真);

//替换MS

args[0]= MsCountMap . get(ms . GetiD);

//查询总数

Object result = .继续;

//还原ms

args[0]= ms;

//设置总数

page.setTotal((整数)((列表)结果)。get(0));

if (page.getTotal == 0) {

返回页面;

}

page . SetTotal(-1l);

}

//pageSize >0,页面大小

if(page . GetPageSize & gt;0 & amp& amp

((rowBounds == RowBounds。DEFAULT & amp& amppage.getPageNum & gt0)

|| rowBounds!= RowBounds。DEFAULT){

//用新的qs替换参数中的MappedStatement

page . setcountssignal;

BoundSql BoundSql = ms . GetBoundSql(args[1]);

args[1]= parser . SetPageParameter(ms,args[1],boundSql,page);

page.setCountSignal(布尔值。FALSE);

//执行分页查询

Object result = .继续;

//获取处理结果

page.a ddAll((List)结果);

}

((PageSqlSource)ms.getSqlSource)。removeParser

}

//返回结果

返回页面;

}

有两个对象结果=调用。继续上面的执行,第一个是执行统计的总数,第二个是执行分页查询的数据

里面用的是特工。最后,第一次返回总页数,第二次获取分页数据。

动词 (verb的缩写)页面助手的使用

上面解释了Mybatis的插件原理和PageHelper的内部实现,下面具体描述了PageHelper的使用

1.首先增加对maven的依赖:

& lt依赖性>。

& ltgroupId>。com . github . page helper & lt;/groupId>。

& ltartifactId>。pagehelper<。/artifactId >

& lt版本>。4.1.6<。/version>。

& lt/依赖性

2.将以下配置添加到configuration.xml文件中(插件应该在环境之上)

& lt插件>。

& lt!-页面帮助4 . 1 . 6->;

& ltplugin interceptor = " com . github . page helper . PageHelper " >;

& ltproperty name= "方言" value="mysql"/>

& ltproperty name = " offsetapagenum " value = " false "/>

& ltproperty name = " RowBoundsWithCount " value = " false "/>

& ltproperty name = " page SiZe zero " value = " true "/>

& ltproperty name= "合理" value="false"/>。

& ltproperty name = " SupportMethodArguments " value = " false "/& gt;

& ltproperty name = " returnPageInfo " value = " none "/& gt;

& lt/plugin>。

& lt/plugins>。

相关的字段描述可以在SqlUtilConfig源代码中找到

当订单不能出现故障时,请注意配置,否则将报告错误

原因:org . Apache . ibatis . builder . Builderexception:创建文档实例时出错。原因:org . XML . sax . SaxParseException;行号:57;列号:17;元素类型为“配置”的内容必须匹配(属性?,设置?,类型别名?,typeHandlers?,objectFactory?,objectWrapperFactory?,外挂?,环境?,databaseIdProvider?mappers?)"。

at org . Apache . ibatis . parsing . XPath parser . create document(XPath parser . Java:259)

at org . Apache . ibatis . parsing . XPath parser . & lt;init>。(XPathParser.java:120)

at org . Apache . ibatis . builder . XML . XMLConfigbuilder . & lt;init>。(XMLConfigBuilder.java:66)

at . org . Apache . ibatis . session . SqlsessionfactoryBuilder . build(SqlsessionfactoryBuilder . Java:49)

...2个以上

这意味着配置中节点的顺序是属性->:设置->;类型别名->;typenhandlers->;对象工厂->;objectwrappperfactory->;插件->;环境->;databaseidProvider->;映射器插件应该在环境之前和objectWrapperFactory之后,这个顺序不能打乱

3.特定用途

1:分页

SqL session = SessionFactory . OpenSession;

user mapper user mapper = SQL session . GetMapper(user mapper . class);

PageHelper.startPage(1,10,true);//第一页每页显示10个项目

页面<。用户>。page = userMapper.findUserAll

2.没有分页

PageHelper.startPage(1,-1,true);

3:查询文章总数

PageInfo<。用户>。info =新页面信息<。>。(user mapper . FindUserAll);

1.《分页控件 Mybatis插件原理和PageHelper结合实战分页插件(七)》援引自互联网,旨在传递更多网络信息知识,仅代表作者本人观点,与本网站无关,侵删请联系页脚下方联系方式。

2.《分页控件 Mybatis插件原理和PageHelper结合实战分页插件(七)》仅供读者参考,本网站未对该内容进行证实,对其原创性、真实性、完整性、及时性不作任何保证。

3.文章转载时请保留本站内容来源地址,https://www.lu-xu.com/shehui/1084817.html

上一篇

休假战士被爆炸气浪冲飞仍救火 现场曝光令人揪心

下一篇

开发商做假地铁站牌忽悠购房者 后续结果是什么

瘊子的最佳治疗方法 治疗寻常疣这三种方法最好不要选!

  • 瘊子的最佳治疗方法 治疗寻常疣这三种方法最好不要选!
  • 瘊子的最佳治疗方法 治疗寻常疣这三种方法最好不要选!
  • 瘊子的最佳治疗方法 治疗寻常疣这三种方法最好不要选!

starnet 值得收藏!基于激光雷达数据的深度学习目标检测方法大合集(下)

  • starnet 值得收藏!基于激光雷达数据的深度学习目标检测方法大合集(下)
  • starnet 值得收藏!基于激光雷达数据的深度学习目标检测方法大合集(下)
  • starnet 值得收藏!基于激光雷达数据的深度学习目标检测方法大合集(下)

信息资源管理方法 2019中国信息资源管理论坛暨第四届大数据与信息资源管理协同创新共同体学术研讨会

  • 信息资源管理方法 2019中国信息资源管理论坛暨第四届大数据与信息资源管理协同创新共同体学术研讨会
  • 信息资源管理方法 2019中国信息资源管理论坛暨第四届大数据与信息资源管理协同创新共同体学术研讨会
  • 信息资源管理方法 2019中国信息资源管理论坛暨第四届大数据与信息资源管理协同创新共同体学术研讨会
瓷管 无主之地3瓷管炸弹怎么得 获得瓷管手雷方法

瓷管 无主之地3瓷管炸弹怎么得 获得瓷管手雷方法

在《无土地3》中,瓷管炸弹是游戏中非常有用的手雷道具,可以杀死一堆敌人或者对BOSS造成致命伤害。如何拿到瓷管弹,下面是具体方法。 在《无土地3》中,瓷管炸弹是游戏中非常有用的手雷道具,可以杀死一堆敌人或者对BOSS造成致命伤害。如何拿到瓷管弹,下面是具体方法。 瓷管炸弹是通过任务获得的。第...

家常火锅鸡的制作方法 正宗重庆肥肠鸡火锅的做法【步骤】

晚上打呼噜的治疗方法 睡觉打呼噜怎么治?

  • 晚上打呼噜的治疗方法 睡觉打呼噜怎么治?
  • 晚上打呼噜的治疗方法 睡觉打呼噜怎么治?
  • 晚上打呼噜的治疗方法 睡觉打呼噜怎么治?

单纯疱疹的治疗方法 这才是口腔单纯性疱疹最快的治疗办法,你也许不知道!

引导语言 你知道口腔单纯疱疹的正确治疗方法吗? 疾病浅析 口腔单纯疱疹病毒(HSV)感染称为口腔单纯疱疹。HSV感染者和病毒携带者是传染源,主要通过直接接触飞沫、唾液和疱疹液,也可通过餐具和衣物间接接触。单纯疱疹病毒感染引起的口腔黏膜病变包括原发性单纯疱疹感染和复发性单纯疱疹感染。 症状表现...

求项数的公式 高中数学:求数列前n项和的七种方法和技巧

求项数的公式 高中数学:求数列前n项和的七种方法和技巧

我们不在乎在高考题或相关试题中是否会出现求数列中N项之和的问题。当然,可能性很大。关键是通过学习和讨论求数列前N项之和的方法,了解学习和思考的方法。几种求和方法结合了数学变形与分析、归纳与总结、简化与困难的思想,系统地训练和提高思维。学习的主要目的是开阔思维,提高思维。 通常有以下七种方法和...