MyBatis分页插件PageHelper自定义分页逻辑实现

2023-05-16

        因为PageHelper对于MySQL的分页逻辑采用的是SQL后面追加limit子句的方式,这样在小数据量情况下是没有问题的。但是对于大数据量的时候,比如limit 100000, 10,MySQL的运作机理是查出100010条数据,再抛弃掉前100000条,留下剩余10条数据。所以执行效率并不高。

        对于MySQL分页SQL的优化我在之前总结过《MySQL查询优化》,无非就是写个自关联,先走内部的主键索引/覆盖索引,这个效率很高。因为每页的数据一般都是10条,所以查出来的数据在和外部做关联的时候即使没有走索引,也不会慢。

        正好在网上也没有搜到相关的自定义实现,所以我就在想能不能自己重写PageHelper中的分页逻辑。在看了看PageHelper源码中相关的实现后发现,PageHelper的分页逻辑是写在了AbstractHelperDialect类中,而不同的数据库分页实现是通过继承实现抽象方法的方式来实现的。对于MySQL的分页就是MySqlDialect类,典型的模板方法模式。

        再来查看MySqlDialect类的实现:

        可以看到就是重写了父类的两个抽象方法,processPageParameter方法是用来处理分页参数的,这个方法不需要管。而下面的getPageSql方法才是用来拼接分页SQL的,可以看到就是简单追加limit子句的方式。看到这里其实就能想到自己再写一个Dialect类,继承MySqlDialect类,覆写其中的getPageSql方法即可实现想要的自定义分页逻辑:

public class MyMySqlDialect extends MySqlDialect {

    @Override
    public String getPageSql(String sql, Page page, CacheKey pageKey) {
        //实现自定义分页逻辑
    }
}

        写完了自定义的分页逻辑后,要想用到它需要做下面的配置:

pagehelper.helperDialect=com.hys.pagehelper.config.MyMySqlDialect

        因为暂时没找到相关的抓取SQL中各个部分的源码(比如表名、字段名等等),只看到了分页的参数,所以我决定自己来实现。我是用正则表达式来实现的(正则大法好),我之前也写过讲解正则表达式的文章《Java中的正则表达式概述》,感兴趣的可以查看。同时我之前也写过一个抓取出不同数据库SQL中的源表和目标表的解析器HSP,也是用正则表达式来实现的。

        下面演示一下我重写的分页逻辑的执行效果。首先是XML中的SQL:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD//EN Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.hys.pagehelper.dao.UserDAO">

    <sql id="allColumns">
        id,
		name,
		sex,
		address
	</sql>

    <select id="list" resultType="com.hys.pagehelper.entity.UserDO">
        SELECT
        <include refid="allColumns"/>
        FROM user
    </select>

</mapper>

        可以看到就是需要对user表进行分页处理。使用的话跟原生的PageHelper类的使用是没有区别的,manager层:

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hys.pagehelper.dao.UserDAO;
import com.hys.pagehelper.entity.Pager;
import com.hys.pagehelper.entity.UserDO;
import com.hys.pagehelper.util.PageHelperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
 * 用户Manager
 *
 * @author Robert Hou
 * @since 2020年11月28日 10:59
 **/
@Component
public class UserManager {

    @Autowired
    private UserDAO userDAO;

    public Pager<UserDO> list(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<UserDO> list = userDAO.list();
        return PageHelperUtils.pageTransform(list);
    }
}

        主要看一下重写的自定义分页实现的代码:

import com.github.pagehelper.Page;
import com.github.pagehelper.dialect.helper.MySqlDialect;
import com.hys.pagehelper.exception.ParseException;
import com.hys.pagehelper.util.PageHelperUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.cache.CacheKey;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * 自定义MySQL分页逻辑
 *
 * @author Robert Hou
 * @since 2020年11月27日 17:45
 **/
@Slf4j
public class MyMySqlDialect extends MySqlDialect {

    private static final Pattern PATTERN = Pattern.compile("SELECT\\s*([\\s|\\S]*?)\\s*?((FROM\\s*[0-9a-zA-Z_`]*)\\s*[\\s|\\S]*)", Pattern.CASE_INSENSITIVE);
    private static final Pattern CONTAINS_JOIN_PATTERN = Pattern.compile("[\\s|\\S]*JOIN[\\s|\\S]*", Pattern.CASE_INSENSITIVE);
    private static final Pattern CONTAINS_DISTINCT_PATTERN = Pattern.compile("\\s+DISTINCT\\s+", Pattern.CASE_INSENSITIVE);
    private static final Pattern CONTAINS_ALIAS_PATTERN = Pattern.compile("\\s*(\\S+)(\\s+AS\\s+\\S+)?\\s*", Pattern.CASE_INSENSITIVE);
    private static final Pattern CONTAINS_GROUP_BY_PATTERN = Pattern.compile("[\\s|\\S]*GROUP\\s+BY[\\s|\\S]*", Pattern.CASE_INSENSITIVE);
    private static final Pattern CONTAINS_ORDER_BY_PATTERN = Pattern.compile("[\\s|\\S]*ORDER\\s+BY[\\s|\\S]*", Pattern.CASE_INSENSITIVE);

    @Override
    public String getPageSql(String sql, Page page, CacheKey pageKey) {
        Matcher containsJoinMatcher = CONTAINS_JOIN_PATTERN.matcher(sql);
        if (containsJoinMatcher.find() || BooleanUtils.isTrue(PageHelperUtils.getIsRelegated())) {
            //多表分页逻辑没实现,用默认的SQL后面追加LIMIT子句的方式(对于不是JOIN方式来进行表连接的SQL(比如笛卡尔积),执行可能会报错。这个时候需要手动将降级选项置为true)
            log.info("使用了多表联查的SQL、或是手动将降级选项置为true的SQL,不会进行优化,而是转而使用默认的SQL后面追加LIMIT子句的方式");
            return invokeSuperMethod(sql, page, pageKey);
        }
        Matcher containsGroupByMatcher = CONTAINS_GROUP_BY_PATTERN.matcher(sql);
        Matcher containsOrderByMatcher = CONTAINS_ORDER_BY_PATTERN.matcher(sql);
        if (containsGroupByMatcher.find() || containsOrderByMatcher.find()) {
            //todo GROUP_BY和ORDER_BY语句没有适配,暂时先降级
            return invokeSuperMethod(sql, page, pageKey);
        }

        log.info("\n原始SQL:\n{}", sql);
        List<String> keyNames = PageHelperUtils.getKeyNames();
        if (CollectionUtils.isEmpty(keyNames)) {
            //没有添加@KeyNamesStrategy注解,也将表主键名设置为”id“
            PageHelperUtils.setKeyNames(new String[]{"id"});
            keyNames = PageHelperUtils.getKeyNames();
        }

        String fromTable = null;
        String fields = null;
        String afterClause = null;
        boolean isSucceeded = false;

        Matcher m = PATTERN.matcher(sql);

        boolean isDistinctContains = false;
        if (m.find()) {
            isSucceeded = true;

            //SELECT后面FROM前面的查找字段
            fields = m.group(1);

            if (isOnlyContainsPrimaryKey(fields)) {
                //如果字段中只包含主键的话,则不需要优化(因为要查的字段都在B+树上,不需要回表进行查询)。改用默认的SQL后面追加LIMIT子句的方式
                log.info("要查询的字段中只包含主键,不需要优化,转而使用默认的SQL后面追加LIMIT子句的方式");
                return invokeSuperMethod(sql, page, pageKey);
            }

            if (fields != null) {
                //查看SQL中是否含有DISTINCT
                Matcher containsDistinctMatcher = CONTAINS_DISTINCT_PATTERN.matcher(sql);
                if (containsDistinctMatcher.find()) {
                    isDistinctContains = true;
                }

                StringBuilder stringBuilder = new StringBuilder();
                for (String keyName : keyNames) {
                    String regex = "[\\s]*[^\\S]+((`)?" + keyName + "(`)?)[^\\S]+[\\s]*";
                    Pattern containsPattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
                    String[] fieldArray = fields.split(",");
                    List<String> fieldList = new ArrayList<>(fieldArray.length);
                    for (String field : fieldArray) {
                        stringBuilder.delete(0, stringBuilder.length());
                        field = stringBuilder.append(" ").append(field).append(" ").toString();
                        Matcher matcher = containsPattern.matcher(field);
                        if (matcher.find()) {
                            String keyNameAndBackQuoteIfContains = matcher.group(1).toUpperCase();
                            //只替换第一个是为了解决表主键起别名的情况
                            fieldList.add(field.toUpperCase().replaceFirst(keyNameAndBackQuoteIfContains, "pageHelperAlias1." + keyNameAndBackQuoteIfContains));
                        } else {
                            fieldList.add(field);
                        }
                    }
                    if (!fieldList.isEmpty()) {
                        fields = String.join(",", fieldList);
                    }
                }
            }

            //FROM+后面的子句
            afterClause = m.group(2);
            if (page.getStartRow() == 0) {
                afterClause = afterClause + "\n LIMIT ? ";
            } else {
                afterClause = afterClause + "\n LIMIT ?, ? ";
            }

            //FROM+表名
            fromTable = m.group(3);
        }
        if (!isSucceeded) {
            throw new ParseException("解析失败!需要排查SQL!");
        }

        String returnSql = "SELECT " + fields + " " + fromTable + " pageHelperAlias1 \n" +
                " INNER JOIN ( SELECT " + (isDistinctContains ? "DISTINCT " : "") + getKeyNames(keyNames) + " " + afterClause + " ) pageHelperAlias2"
                + joinKeyNames(keyNames);
        log.info("\n拼接后的分页SQL:\n{}", returnSql);

        PageHelperUtils.remove();
        return returnSql;
    }

    private String invokeSuperMethod(String sql, Page<?> page, CacheKey pageKey) {
        PageHelperUtils.remove();
        return super.getPageSql(sql, page, pageKey);
    }

    /**
     * KeyNames转换成String格式(逗号拼接)
     */
    private String getKeyNames(List<String> keyNames) {
        if (CollectionUtils.isEmpty(keyNames)) {
            return null;
        }

        StringBuilder stringBuilder = new StringBuilder();
        for (String keyName : keyNames) {
            stringBuilder.append(keyName.trim()).append(", ");
        }
        stringBuilder.deleteCharAt(stringBuilder.length() - 2);
        return stringBuilder.toString();
    }

    /**
     * KeyNames转换成SQL JOIN的关联格式
     */
    private String joinKeyNames(List<String> keyNames) {
        if (CollectionUtils.isEmpty(keyNames)) {
            return null;
        }

        StringBuilder stringBuilder = new StringBuilder(" ON ");
        for (int i = 0; i < keyNames.size(); i++) {
            keyNames.set(i, keyNames.get(i).trim());
            stringBuilder.append("pageHelperAlias1.").append(keyNames.get(i)).append(" = pageHelperAlias2.").append(keyNames.get(i));
            if (i != keyNames.size() - 1) {
                stringBuilder.append(" AND ");
            }
        }
        return stringBuilder.toString();
    }

    /**
     * 判断字段中是否只包含主键
     */
    private boolean isOnlyContainsPrimaryKey(String fields) {
        if (StringUtils.isBlank(fields)) {
            return false;
        }

        List<String> keyNames = PageHelperUtils.getKeyNames();
        if (CollectionUtils.isEmpty(keyNames)) {
            return false;
        }
        //考虑keyNames有可能有重复主键名的情况 e.g.@KeyNamesStrategy(keyNames = {"order_id", "order_id"})
        List<String> uniqueKeyNames = unique(keyNames);
        String[] fieldArray = fields.split(",");
        List<String> uniqueFieldArray = unique(fieldArray);
        int length = 0;
        for (String field : uniqueFieldArray) {
            if (!uniqueKeyNames.contains(field)) {
                return false;
            }
            length++;
        }
        return length == uniqueKeyNames.size();
    }

    private String removeAliasAndBackQuoteIfContains(String field) {
        if (StringUtils.isBlank(field)) {
            return StringUtils.EMPTY;
        }

        Matcher matcher = CONTAINS_ALIAS_PATTERN.matcher(field);
        if (matcher.find()) {
            String keyNameAndBackQuoteIfContains = matcher.group(1);
            if (keyNameAndBackQuoteIfContains.startsWith("`") && keyNameAndBackQuoteIfContains.endsWith("`")) {
                return keyNameAndBackQuoteIfContains.substring(1, keyNameAndBackQuoteIfContains.length() - 1);
            }
            return keyNameAndBackQuoteIfContains;
        }
        return field;
    }

    private List<String> unique(List<String> list) {
        if (CollectionUtils.isEmpty(list)) {
            return Collections.emptyList();
        }

        return list.stream().map(this::removeAliasAndBackQuoteIfContains).distinct().collect(Collectors.toList());
    }

    private List<String> unique(String[] array) {
        if (ArrayUtils.isEmpty(array)) {
            return Collections.emptyList();
        }

        List<String> list = Arrays.stream(array).collect(Collectors.toList());
        return unique(list);
    }
}

        下面演示一下执行效果:

原始SQL:
SELECT
         
        id,
		name,
		sex,
		address
	 
        FROM user
拼接后的分页SQL:
SELECT pageHelperAlias1.id,
		name,
		sex,
		address FROM user pageHelperAlias1 
 INNER JOIN ( SELECT id  FROM user
 LIMIT ?, ?  ) pageHelperAlias2 ON pageHelperAlias1.id = pageHelperAlias2.id
==>  Preparing: SELECT pageHelperAlias1.id, name, sex, address FROM user pageHelperAlias1 INNER JOIN ( SELECT id FROM user LIMIT ?, ? ) pageHelperAlias2 ON pageHelperAlias1.id = pageHelperAlias2.id
==> Parameters: 10(Long), 10(Integer)
<==      Total: 3

        上面是后台打印的日志,因为我这里的user表的主键是id字段,所以可以看到是能成功分页出来的。而默认的PageHelper类的MySQL分页是简单通过后面追加limit子句的方式来实现的。

        当然我这里的假设是表的主键名一定是“id”。而如果表的主键名不是“id”的话,比如“order_id”,我这里也做了支持。我使用了Spring AOP(自定义注解和环绕通知),只需要在manager层上加上我封装的自定义注解@KeyNamesStrategy就行了:

import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.hys.pagehelper.annotation.KeyNamesStrategy;
import com.hys.pagehelper.dao.UserDAO;
import com.hys.pagehelper.entity.Pager;
import com.hys.pagehelper.entity.UserDO;
import com.hys.pagehelper.util.PageHelperUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * 用户Manager
 *
 * @author Robert Hou
 * @since 2020年11月28日 10:59
 **/
@Component
public class UserManager {

    @Autowired
    private UserDAO userDAO;

    @KeyNamesStrategy(keyNames = "name")
    public Pager<UserDO> list(int pageNum, int pageSize) {
        PageHelper.startPage(pageNum, pageSize);
        Page<UserDO> list = userDAO.list();
        return PageHelperUtils.pageTransform(list);
    }
}

        我这里是假设user表的主键名是“name”,而不再是“id”,再来看一下后台打印的日志:

原始SQL:
SELECT
         
        id,
		name,
		sex,
		address
	 
        FROM user
拼接后的分页SQL:
SELECT id,
		pageHelperAlias1.name,
		sex,
		address FROM user pageHelperAlias1 
 INNER JOIN ( SELECT name  FROM user
 LIMIT ?, ?  ) pageHelperAlias2 ON pageHelperAlias1.name = pageHelperAlias2.name
==>  Preparing: SELECT id, pageHelperAlias1.name, sex, address FROM user pageHelperAlias1 INNER JOIN ( SELECT name FROM user LIMIT ?, ? ) pageHelperAlias2 ON pageHelperAlias1.name = pageHelperAlias2.name
==> Parameters: 10(Long), 10(Integer)
<==      Total: 3

        可以看到也是能成功分页出来的。哪怕是联合主键,比如user表中的“id”和“name”两个字段联合做主键,也可以这么写:

@KeyNamesStrategy(keyNames = {"id", "name"})

        再来看一下后台打印的日志:

原始SQL:
SELECT
         
        id,
		name,
		sex,
		address
	 
        FROM user
拼接后的分页SQL:
SELECT pageHelperAlias1.id,
		pageHelperAlias1.name,
		sex,
		address FROM user pageHelperAlias1 
 INNER JOIN ( SELECT id, name  FROM user
 LIMIT ?, ?  ) pageHelperAlias2 ON pageHelperAlias1.id = pageHelperAlias2.id AND pageHelperAlias1.name = pageHelperAlias2.name
==>  Preparing: SELECT pageHelperAlias1.id, pageHelperAlias1.name, sex, address FROM user pageHelperAlias1 INNER JOIN ( SELECT id, name FROM user LIMIT ?, ? ) pageHelperAlias2 ON pageHelperAlias1.id = pageHelperAlias2.id AND pageHelperAlias1.name = pageHelperAlias2.name
==> Parameters: 10(Long), 10(Integer)
<==      Total: 3

        可以看到也是能成功分页出来的。相关的代码我已经上传到GitHub上了,地址:https://github.com/ACoolMonkey/PageHelper

        介于测试的数据量不大,可能会有bug。同时目前仅支持MySQL单表的分页操作,对于多表连接的分页需求,我这里暂时是没有自定义实现的,会退化成默认的追加limit子句的方式来实现(如果一定要实现,是否可以考虑使用视图View来实现?)。而且对于笛卡尔积那种没有写“JOIN”直接进行连接的SQL,我这里执行可能会报错,这点等以后有时间了再去研究吧,其实对于笛卡尔积来说都可以把SQL改为“JOIN”的方式。如果不想改动的话,我这里也提供一个降级选项:isRelegated。默认值为false,如果设置为true的话,这条SQL就会完全走默认的PageHelper分页的逻辑,而不会走我自定义的分页逻辑(性能要低一些,但是起码能保证不出错)

@KeyNamesStrategy(isRelegated = true)

原创不易,未得准许,请勿转载,翻版必究

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

MyBatis分页插件PageHelper自定义分页逻辑实现 的相关文章

  • Sublime MinGw实现C/C++代码编译运行

    安装配置MinGw 下载安装MinGW 去官网下载MinGw xff1a http www mingw org 或者下载我已经下载好的完整版 xff1a http pan baidu com s 1gfgluin 2017 7 5更新 如图
  • Ajax发送POST请求SpringMVC页面跳转失败

    问题描述 xff1a 因为使用的是SpringMVC框架 xff0c 所以想使用ModelAndView进行页面跳转 思路是发送POST请求 xff0c 然后controller层中直接返回相应ModelAndView xff0c 但是这种
  • Debian命令

    1 dpkg i 安装下载的软件包 2 shutdown h now 关机 3 fdisk l 查看当前盘 4 lspci 用来显示系统中所有PCI总线设备或连接到该总线上的所有设备的工具 如lspci v 参数 xff1a v 使得 ls
  • 堡垒机-teleport的安装以及常见问题解决办法

    teleport是一款简单易用的堡垒机系统 xff0c 运用在企业对windows linux服务器的安全使用管理以及审计 官网网址 xff1a http teleport eomsoft net github地址 xff1a https
  • 【Luogu】P1593因子和(唯一分解定理,约数和公式)

    题目链接 首先介绍两个定理 整数唯一分解定理 xff1a 任意正整数都有且只有一种方式写出素数因子的乘积表达式 A 61 p1k1 p2k2 pnkn 求这些因子的代码如下 for int i 61 2 i i lt 61 a 43 43
  • 通用组件—SvgIcon引入和使用

    Svg Icon 创建一个专门放置图标 icon 的文件夹 xff1a src icons 添加SvgIcon组件到公共components目录下 src components SvgIcon index vue lt template g
  • [HDU3652]B-number

    题面描述 给定一个数 n 求 1 n 中所有满足以下条件的数的个数 xff1a 1 该数中不包含 34 13 34 2 该数能被13整除 输入格式 输入包含多行 xff0c 每行一个整数 n 1 leq n leq 1000000000 输
  • [GYM 101755]Restoring Numbers

    题面描述 已知两个正整数a b的和s与最大公约数g xff0c 求a b 输入格式 一共一行 xff0c 包含两个正整数 s g 输出格式 一共一行 xff0c 若有解输出 a b 否则输出 1 样例数据 样例输入 6 2 样例输出 4 2
  • 数位DP 详解

    序 天堂在左 xff0c 战士向右 引言 数位DP在竞赛中的出现几率极低 xff0c 但是如果不会数位DP xff0c 一旦考到就只能暴力骗分 以下是数位DP详解 xff0c 涉及到的例题有 xff1a HDU2089 不要62 HDU36
  • 关于485通信不稳定问题解决方案[STM32产品问题]

    485通讯不稳定的问题 xff08 具体表现为有时能通讯上 xff0c 有时通讯不上 xff09 RS485在连接设备过多 通讯距离过长 双绞线质量差 xff0c 接线不规范 等 xff0c 都会导致通讯不稳定的问题 解决方案 xff1a
  • Oracle update语句更新值来自另一张表中的数据

    task 任务表 role 角色表 两表之间必须有关联的字段 update task t set t roleName 61 select r name from role r where r id 61 t roleid 转载于 http
  • HTML个人简介

    lt doctype html gt lt html lang 61 34 en 34 gt lt head gt lt meta charset 61 34 UTF 8 34 gt lt meta name 61 34 Generator
  • 如何查看windows某个目录下所有文件/文件夹的大小?

    如何查看windows某个目录下所有文件 文件夹的大小 xff1f TreeSize Free绿色汉化版是一款硬盘空间管理工具 xff0c 用树形描述出来 xff0c 能够显示文件大小和实际占用空间数及浪费的空间等信息 xff0c 让你做出
  • Kafka服务不可用(宕机)问题踩坑记

    背景 某线上日志收集服务报警 xff0c 打开域名报502错误码 收集服务由2台netty HA服务器组成 netty服务器将客户端投递来的protobuf日志解析并发送到kafka xff0c 打开其中一个应用的日志 xff0c 发现如下
  • Sublime Text 的破解方式

    Sublime Text 破解 xff08 Mac和Windows系统 xff09 Posted on 2013 年 11 月 19 日 3 条评论 6 031 次浏览 继 续分享在 Mac OSX 和 Windows 下破解编码神器 xf
  • 洛谷P1233 木棍加工【单调栈】

    题目 xff1a https www luogu org problemnew show P1233 题意 xff1a 有n根木棍 xff0c 每根木棍有长度和宽度 现在要求按某种顺序加工木棍 xff0c 如果前一根木棍的长度和宽度都大于现
  • 高并发核心知识——ZooKeeper

    ZooKeeper 简介 ZooKeeper是一个开源的分布式协调服务 xff0c 重视高性能 高可用 严格有序的访问 Zookeeper中利用被称为znode的节点保存数据 xff0c 数据将保存在内存 ram 中 xff0c 最多存储1
  • https://gns3.com/community/discussion/gns3-doesn-t-work-on-vmware-play

    swered Question GNS3 doesn t work on VMWARE player 15 Hi guys today I try to install GNS3 on new VMWARE player 15 with V
  • 时间同步服务

    1 NTP时钟同步方式说明 NTP在linux下有两种时钟同步方式 xff0c 分别为直接同步和平滑同步 xff1a 直接同步 使用ntpdate命令进行同步 xff0c 直接进行时间变更 如果服务器上存在一个12点运行的任务 xff0c
  • The Windows 10 May 2020 Update无法更新问题,从1909升级到2004

    今天系统在更新的时候遇到系统提示如下信息 The Windows 10 May 2020 Update is on its way We re offering this update to compatible devices but y

随机推荐

  • 遇到Visual Studio "当前不会命中断点.还没有为该文档加载任何符号"的情况

    一 问题及原因 有这样一种调用逻辑 A exe调用B dll 现在想要在B的源代码中打断点 从A发起进行调试 却给出了 34 当前不会命中断点 还没有为该文档加载任何符号 34 的提示 感觉十分奇怪 各种重新生成 重启VS都没啥用 最后不得
  • Centos 7 Ntop 流量分析 安装

    Centos 6 安装 Ntop xff1a https www cnblogs com weijie0717 p 4886314 html 一 安装 1 添加EPEL 仓库 yum install epel release 2 创建 Nt
  • 三节点搭建openstack-Mitaka版本

    前言 xff1a 现在的云计算平台已经非常火 xff0c 也非常的稳定了 像阿里云平台 xff0c 百度云平台等等 xff0c 今天咱们基于openstack来搭建一个云平台 注意 xff1a 本次平台搭建为三节点搭建 xff08 没有外部
  • POJ滑动窗口

    题目描述 现在有一堆数字共N个数字 xff08 N lt 61 10 6 xff09 xff0c 以及一个大小为k的窗口 现在这个从左边开始向右滑动 xff0c 每次滑动一个单位 xff0c 求出每次滑动后窗口中的最大值和最小值 例如 xf
  • JsonSQL:用SQL语句解析JSON文件

    下午没事干 xff0c 到处闲逛发现一个好玩的东东 xff0c 发出来与大家共享 xff0c 哈哈 一个解析JSON的插件 xff0c 用SQL语法 xff0c 当然只能用简单的条件查询咯 xff0c 不过这个用起比较简单 xff0c 容易
  • windows系统cmd命令行设置、查看、更改环境变量

    问题场景 xff1a 在windows系统 xff0c 做flask项目需要配置qq邮箱的用户 密码 xff0c 为了安全性账户密码需要从OA机的环境变量中设置 获取 xff1a code import os app config 39 M
  • Python之路【第二十五篇】:数据库之pymysql模块

    数据库进阶 一 pymysql模块 pymysql是Python中操作Mysql的模块 xff0c 其使用的方法和py2的MySQLdb几乎相同 二 pymysql模块安装 pip install pymysql 三 执行sql语句 cod
  • centos7 linux中搭建MFS分布式文件系统

    MFS分布式文件系统 mooseFS xff08 moose 驼鹿 xff09 是一款网络分布式文件系统 它把数据分散在多台服务器上 xff0c 但对于用户来讲 xff0c 看到的只是一个源 MFS也像其他类unix文件系统一样 xff0c
  • MAC_BOOKPRO苹果电脑系统常用快捷键大全

    Mac 键盘快捷键 我在品多多上拼的Mac终于到货了 xff0c 安全下车 xff0c 接下来要熟练使用了 xff01 您可以按下某些组合键来实现通常需要鼠标 触控板或其他输入设备才能完成的操作 要使用键盘快捷键 xff0c 请按住一个或多
  • 微信小程序web-view(webview) 嵌套H5页面 唤起微信支付的实现方案

    场景 小程序页面有一个web view组件 xff0c 组件嵌套的H5页面 xff0c 要唤起微信支付 先讲一下我的项目 xff0c 首先我是自己开发的一个H5触屏版的商城系统 xff0c 里面含有购物车 xff0c 订单支付等功能 然后刚
  • Linux-常用命令

    基本命令 查看文件 span class token function ls span span class token comment 列出当前目录文件和文件夹名称 span F span class token comment 输出可以
  • 酒店管理系统(功能结构图、E-R图、用例图)

    功能结构图 用例图 状态图 流程图 数据字典 er图 转载于 https www cnblogs com wang jee p 10828875 html
  • C语言表达分段函数

    void main int x y scanf 34 d 34 amp x if x lt 61 1 y 61 x else if x gt 1 amp amp x lt 10 y 61 2 x 1 else if x gt 61 10 y
  • 拼音转汉字

    description Pinyin to get chinese pinyin from chinese license MIT style authors Bill Lue requires core 1 2 1 39 39 provi
  • windows下C++连接mysql

    平台 xff1a windows c c 43 43 编译器 xff1a vs2017 项目设置 xff1a 项目属性页 xff1a 1 C C 43 43 gt 常规 gt 附加包含目录 gt C Program Files x86 My
  • 制表符概念的理解(c语言角度)

    百度百科给出的答案 xff1a 制表符 xff08 也叫制表位 的功能是在不使用表格的情况下在垂直方向按列对齐文本 比较常见的应用包括名单 简单列表等 也可以应用于制作页眉页脚等同一行有几个对齐位置的行 至于制表符这一概念的由来 xff0c
  • iOS中实现多线程的技术方案

    pthread 实现多线程操作 代码实现 xff1a void run void param for NSInteger i 61 0 i lt 1000 i 43 43 NSLog 64 34 buttonclick zd 64 34 i
  • linux inode 详解 / 线上inode爆满解决方案

    linux inode 详解 线上inode爆满解决方案 本文大量参考阮一峰大神博客 xff0c 整理笔记 之所以写inode文章是由于一次线上问题 xff0c 引发对inode深入的思考 磁盘的inode监控与磁盘空间的监控同等重要 xf
  • vscode调整字体大小

    在vscode中 xff0c 通过setting gt User gt Text Editor gt Font可以调整字体大小 xff0c 但是这里只是调整右侧的代码编辑区域的字体 xff0c 左侧的侧边栏确无法调整字体大小 xff0c 找
  • MyBatis分页插件PageHelper自定义分页逻辑实现

    因为PageHelper对于MySQL的分页逻辑采用的是SQL后面追加limit子句的方式 xff0c 这样在小数据量情况下是没有问题的 但是对于大数据量的时候 xff0c 比如limit 100000 10 xff0c MySQL的运作机