当前位置: 首页 > news >正文

瑞丽航空公司官方网站wordpress客户端插件下载

瑞丽航空公司官方网站,wordpress客户端插件下载,中国建筑材料网官网,动漫公司网站建设目录 分页插件 Mybatis插件典型适用场景 实现思考 第一个问题 第二个问题 自定义分页插件 分页插件使用 添加pom依赖 插件注册 调用 代理和拦截是怎么实现的 PageHelper 原理 分页插件 MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBati…

目录

分页插件

Mybatis插件典型适用场景

实现思考

第一个问题

第二个问题

自定义分页插件

分页插件使用

添加pom依赖

插件注册

调用

代理和拦截是怎么实现的

PageHelper 原理


分页插件

MyBatis 通过提供插件机制,让我们可以根据自己的需要去增强MyBatis 的功能。需要注意的是,如果没有完全理解MyBatis 的运行原理和插件的工作方式,最好不要使用插件,因为它会改变系底层的工作逻辑,给系统带来很大的影响。

MyBatis 的插件可以在不修改原来的代码的情况下,通过拦截的方式,改变四大核心对象的行为,比如处理参数,处理SQL,处理结果。

Mybatis插件典型适用场景

分页功能

mybatis的分页默认是基于内存分页的(查出所有,再截取),数据量大的情况下效率较低,不过使用mybatis插件可以改变该行为,只需要拦截StatementHandler类的prepare方法,改变要执行的SQL语句为分页语句即可;

公共字段统一赋值

一般业务系统都会有创建者,创建时间,修改者,修改时间四个字段,对于这四个字段的赋值,实际上可以在DAO层统一拦截处理,可以用mybatis插件拦截Executor类的update方法,对相关参数进行统一赋值即可;

性能监控

对于SQL语句执行的性能监控,可以通过拦截Executor类的update, query等方法,用日志记录每个方法执行的时间;

其它

其实mybatis扩展性还是很强的,基于插件机制,基本上可以控制SQL执行的各个阶段,如执行阶段,参数处理阶段,语法构建阶段,结果集处理阶段,具体可以根据项目业务来实现对应业务逻辑。

实现思考

第一个问题

 不修改对象的代码,怎么对对象的行为进行修改,比如说在原来的方法前面做一点事情,在原来的方法后面做一点事情?

  答案:大家很容易能想到用代理模式,这个也确实是MyBatis 插件的原理。

第二个问题

我们可以定义很多的插件,那么这种所有的插件会形成一个链路,比如我们提交一个休假申请,先是项目经理审批,然后是部门经理审批,再是HR 审批,再到总经理审批,怎么实现层层的拦截?

  答案:插件是层层拦截的,我们又需要用到另一种设计模式——责任链模式。

在之前的源码中我们也发现了,mybatis内部对于插件的处理确实使用的代理模式,既然是代理模式,我们应该了解MyBatis 允许哪些对象的哪些方法允许被拦截,并不是每一个运行的节点都是可以被修改的。只有清楚了这些对象的方法的作用,当我们自己编写插件的时候才知道从哪里去拦截。在MyBatis 官网有答案,我们来看一下:

mybatis – MyBatis 3 | 配置

Executor 会拦截到CachingExcecutor 或者BaseExecutor。因为创建Executor 时是先创建CachingExcecutor,再包装拦截。从代码顺序上能看到。我们可以通过mybatis的分页插件来看看整个插件从包装拦截器链到执行拦截器链的过程。

  在查看插件原理的前提上,我们需要来看看官网对于自定义插件是怎么来做的,官网上有介绍:通过 MyBatis 提供的强大机制,使用插件是非常简单的,只需实现 Interceptor 接口,并指定想要拦截的方法签名即可。这里本人踩了一个坑,在Springboot中集成,同时引入了pagehelper-spring-boot-starter 导致RowBounds参数的值被刷掉了,也就是走到了我的拦截其中没有被设置值,这里需要注意,拦截器出了问题,可以Debug看一下Configuration配置类中拦截器链的包装情况。

自定义分页插件

@Intercepts({@Signature(type = Executor.class,method = "query" ,args ={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class} ), // 需要代理的对象和方法@Signature(type = Executor.class,method = "query" ,args ={MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class} ) // 需要代理的对象和方法
})
public class MyPageInterceptor implements Interceptor {@Overridepublic Object intercept(Invocation invocation) throws Throwable {System.out.println("简易版的分页插件:逻辑分页改成物理分页");// 修改sql 拼接Limit 0,10Object[] args = invocation.getArgs();// MappedStatement 对mapper映射文件里面元素的封装MappedStatement ms= (MappedStatement) args[0];// BoundSql 对sql和参数的封装Object parameterObject=args[1];BoundSql boundSql = ms.getBoundSql(parameterObject);// RowBounds 封装了逻辑分页的参数 :当前页offset,一页数limitRowBounds rowBounds= (RowBounds) args[2];// 拿到原来的sql语句String sql = boundSql.getSql();String limitSql=sql+ " limit "+rowBounds.getOffset()+","+ rowBounds.getLimit();//将分页sql重新封装一个BoundSql 进行后续执行BoundSql pageBoundSql = new BoundSql(ms.getConfiguration(), limitSql, boundSql.getParameterMappings(), parameterObject);// 被代理的对象Executor executor= (Executor) invocation.getTarget();CacheKey cacheKey = executor.createCacheKey(ms, parameterObject, rowBounds, pageBoundSql);// 调用修改过后的sql继续执行查询return  executor.query(ms,parameterObject,rowBounds, (ResultHandler) args[3],cacheKey,pageBoundSql);}
}

拦截签名跟参数的顺序有严格要求,如果按照顺序找不到对应方法会抛出异常:

org.apache.ibatis.exceptions.PersistenceException: ### Error opening session. Cause: org.apache.ibatis.plugin.PluginException: Could not find method on interface org.apache.ibatis.executor.Executor named query

MyBatis 启动时扫描 标签, 注册到Configuration 对象的 InterceptorChain 中。property 里面的参数,会调用setProperties()方法处理。

分页插件使用

添加pom依赖

<dependency><groupId>com.github.pagehelper</groupId><artifactId>pagehelper</artifactId><version>1.2.15</version>
</dependency>

插件注册

在mybatis-config.xml 中注册插件

<configuration><plugins><!-- com.github.pagehelper为PageHelper类所在包名 --><plugin interceptor="com.github.pagehelper.PageHelper"><property name="helperDialect" value="mysql" /><!-- 该参数默认为false --><!-- 设置为true时,会将RowBounds第一个参数offset当成pageNum页码使用 --><!-- 和startPage中的pageNum效果一样 --><property name="offsetAsPageNum" value="true" /><!-- 该参数默认为false --><!-- 设置为true时,使用RowBounds分页会进行count查询 --><property name="rowBoundsWithCount" value="true" /><!-- 设置为true时,如果pageSize=0或者RowBounds.limit = 0就会查询出全部的结果 --><!-- (相当于没有执行分页查询,但是返回结果仍然是Page类型) --><property name="pageSizeZero" value="true" /><!-- 3.3.0版本可用 - 分页参数合理化,默认false禁用 --><!-- 启用合理化时,如果pageNum<1会查询第一页,如果pageNum>pages会查询最后一页 --><!-- 禁用合理化时,如果pageNum<1或pageNum>pages会返回空数据 --><property name="reasonable" value="true" /><!-- 3.5.0版本可用 - 为了支持startPage(Object params)方法 --><!-- 增加了一个`params`参数来配置参数映射,用于从Map或ServletRequest中取值 --><!-- 可以配置pageNum,pageSize,count,pageSizeZero,reasonable,不配置映射的用默认值 --><!-- 不理解该含义的前提下,不要随便复制该配置 --><property name="params" value="pageNum=start;pageSize=limit;" /></plugin></plugins>
</configuration>

调用

// 获取配置文件
InputStream inputStream = Resources.getResourceAsStream("mybatis/mybatis-config.xml");
// 通过加载配置文件获取SqlSessionFactory对象
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
try (SqlSession sqlSession = sqlSessionFactory.openSession()) {// Mybatis在getMapper就会给我们创建jdk动态代理EmpMapper mapper = sqlSession.getMapper(EmpMapper.class);PageHelper.startPage(1, 5);List<Emp> list=mapper.selectAll(); PageInfo<ServiceStation> info = new PageInfo<ServiceStation>(list, 3);                   System.out.println("当前页码:"+info.getPageNum());System.out.println("每页的记录数:"+info.getPageSize());System.out.println("总记录数:"+info.getTotal());System.out.println("总页码:"+info.getPages());System.out.println("是否第一页:"+info.isIsFirstPage());System.out.println("连续显示的页码:");int[] nums = info.getNavigatepageNums();for (int i = 0; i < nums.length; i++) {System.out.println(nums[i]);}     
}  

代理和拦截是怎么实现的

上面提到的可以被代理的四大对象都是什么时候被代理的呢?Executor 是openSession() 的时候创建的; StatementHandler 是SimpleExecutor.doQuery()创建的;里面包含了处理参数的ParameterHandler 和处理结果集的ResultSetHandler 的创建,创建之后即调用InterceptorChain.pluginAll(),返回层层代理后的对象。代理是由Plugin 类创建。在我们重写的 plugin() 方法里面可以直接调用returnPlugin.wrap(target, this);返回代理对象。

当个插件的情况下,代理能不能被代理?代理顺序和调用顺序的关系? 可以被代理。

因为代理类是Plugin,所以最后调用的是Plugin 的invoke()方法。它先调用了定义的拦截器的intercept()方法。可以通过invocation.proceed()调用到被代理对象被拦截的方法。

调用流程时序图:

PageHelper 原理

先来看一下分页插件的简单用法:

PageHelper.startPage(1, 3);

List<Blog> blogs = blogMapper.selectBlogById2(blog); PageInfo page = new PageInfo(blogs, 3);

对于插件机制我们上面已经介绍过了,在这里我们自然的会想到其所涉及的核心类 :PageInterceptor。拦截的是Executor 的两个query()方法,要实现分页插件的功能,肯定是要对我们写的sql进行改写,那么一定是在 intercept 方法中进行操作的,我们会发现这么一行代码:

String pageSql = this.dialect.getPageSql(ms, boundSql, parameter, rowBounds, cacheKey);

 调用到 AbstractHelperDialect 中的  getPageSql 方法:

public String getPageSql(MappedStatement ms, BoundSql boundSql, Object parameterObject, RowBounds rowBounds, CacheKey pageKey) {// 获取sqlString sql = boundSql.getSql();//获取分页参数对象Page page = this.getLocalPage();return this.getPageSql(sql, page, pageKey);}

这里可以看到会去调用 this.getLocalPage(),我们来看看这个方法:

public <T> Page<T> getLocalPage() {return PageHelper.getLocalPage();
}
//线程独享
protected static final ThreadLocal<Page> LOCAL_PAGE = new ThreadLocal();
public static <T> Page<T> getLocalPage() {return (Page)LOCAL_PAGE.get();
}

可以发现这里是调用的是PageHelper的一个本地线程变量中的一个 Page对象,从其中获取我们所设置的  PageSize 与 PageNum,那么他是怎么设置值的呢?请看:

PageHelper.startPage(1, 3);public static <E> Page<E> startPage(int pageNum, int pageSize) {return startPage(pageNum, pageSize, true);
}public static <E> Page<E> startPage(int pageNum, int pageSize, boolean count, Boolean reasonable, Boolean pageSizeZero) {Page<E> page = new Page(pageNum, pageSize, count);page.setReasonable(reasonable);page.setPageSizeZero(pageSizeZero);Page<E> oldPage = getLocalPage();if (oldPage != null && oldPage.isOrderByOnly()) {page.setOrderBy(oldPage.getOrderBy());}//设置页数,行数信息setLocalPage(page);return page;
}protected static void setLocalPage(Page page) {//设置值LOCAL_PAGE.set(page);
}

在我们调用 PageHelper.startPage(1, 3); 的时候,系统会调用 LOCAL_PAGE.set(page) 进行设置,从而在分页插件中可以获取到这个本地变量对象中的参数进行 SQL 的改写,由于改写有很多实现,我们这里用的Mysql的实现:

在这里我们会发现分页插件改写SQL的核心代码,这个代码就很清晰了,不必过多赘述:

public String getPageSql(String sql, Page page, CacheKey pageKey) {StringBuilder sqlBuilder = new StringBuilder(sql.length() + 14);sqlBuilder.append(sql);if (page.getStartRow() == 0) {sqlBuilder.append(" LIMIT ");sqlBuilder.append(page.getPageSize());} else {sqlBuilder.append(" LIMIT ");sqlBuilder.append(page.getStartRow());sqlBuilder.append(",");sqlBuilder.append(page.getPageSize());pageKey.update(page.getStartRow());}pageKey.update(page.getPageSize());return sqlBuilder.toString();
}

PageHelper 就是这么一步一步的改写了我们的SQL 从而达到一个分页的效果。

关键类总结:

http://www.yayakq.cn/news/710607/

相关文章:

  • 网站建设和管理专业做问卷的几个网站
  • 常州网站搜索优化营销型网站建设的步骤
  • 企业管理网站建设wordpress 支付下载
  • 做钢材的网站做淘宝货源网站
  • 做网站意义哪些外贸网站比较好
  • 东海做网站公司建筑网站搜图
  • 企业网站建设公司有哪些公司页面图片
  • 做国内打不开的网站吗php网站建设题目
  • 免费网站cmswordpress数据库搜索功能
  • 网站建设广州白云wordpress做dropping
  • 广丰区建设局网站重庆忠县网站建设报价
  • 教育网页设计网站360极速怎么屏蔽网站
  • 建设视频网站的视频源saas微信小程序开发工具
  • 凡科网站做门户网怎么样wordpress 社区 插件
  • 朋友用我的vps做网站宁波拳头信息科技有限公司
  • 开发商城网站公司手机网站 好处
  • 备份核验单时网站域名做网站工作内容
  • 免费做图片的网站有哪些wordpress 主页显示多图
  • 广东品牌网站制作公司天津网站建设学习
  • 贵州企业网站建设公司回合网页游戏排行榜前十名
  • 找客户资源的网站福州住房和建设局网站
  • 做视频赚钱的网站北京网站开发网络公司
  • 福建住房和建设网站密码忘记购彩网站建设
  • 做第三方库个人网站网站开发经营范围
  • 网站功能建设规划书网站程序授权怎么做
  • 网站的倒计时怎么做小型企业网站建设的背景
  • 嘉兴营销型网站手机版网站开发
  • 响应式网站模块优化关键词排名工具
  • 怀化网站优化乐从网站建设公司
  • 上海平台网站建设公司排名网站seo优化推广教程