8分钟搭建Yapi小教程

废话不多说,直接安装吧~

一、安装nodejs

1.获取资源(部署nodejs尽可能选择偶数版本,因为偶数版本官方有较长的维护时间,故这次选择8.x。)

curl -sL https://rpm.nodesource.com/setup_8.x | bash -

2.安装node.js

yum install -y nodejs

3.查看版本检验是否安装成功

node -v

4.查看npm版本

npm -v
阅读全文 »

大文件小内存排序问题(阿里笔试题)

关于大文件小内存的问题很常见,今天心血来潮想试试自己写一下这个代码。

1.生成4G的数字文本文件

通过计算每行的字节大小,累加到4G的话就停止写入

 /**
 * 生成一个4G的文件
 *
 * @param file
 * @throws IOException
 */
public static void makeBigFile(File file) throws IOException {

    FileOutputStream fos = new FileOutputStream(file);

    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"));
    // 随机数生成种子
    Random rand = new Random(1);

    long fileByteLength = 0;
    // BIG_FILE_SIZE为4G
    while (fileByteLength < BIG_FILE_SIZE) {

        String randomIntStr = rand.nextInt(1000000000) + "";
        bw.write(randomIntStr);
        bw.newLine();

        // 文件大小等于数字字符串的字符串字节大小加上换行符为两个字节
        fileByteLength += randomIntStr.getBytes().length + 2;

    }

    bw.close();

}

2.将大文件分割为256mb的小文件在内存中进行排序

当超过256mb文件时,即更换另一个新的文件。(第一次写,条件没设置好,结果生成了一百多万个空文件,删除花了N久)

 /**
 * 将大文件拆分为不同的小文件
 *
 * @param bigFile 4G大文件
 * @throws IOException
 */
public static void splitBigFileToSmallFile(File bigFile, String dirStr) throws IOException {

    // 提前创建目录
    File dir = new File(dirStr);

    if (!dir.exists()) {
        dir.mkdirs(); //创建目录
    }

    BufferedInputStream fis = new BufferedInputStream(new FileInputStream(bigFile));

    // 用5M的缓冲读取文本文件
    BufferedReader reader = new BufferedReader(new InputStreamReader(fis, "utf-8"), BUFFER_SIZE);

    String line = null;

    int fileNum = 1;
    long smallFileByteLength = 0;


    File smallFile = new File(dirStr + fileNum + ".txt");
    FileOutputStream fos = new FileOutputStream(smallFile);

    BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"));

    while ((line = reader.readLine()) != null) {

        smallFileByteLength += getRowByteLength(line);

        bw.write(line);
        bw.newLine();

        // 当文件超过固定大小的话,进行拆分
        if (smallFileByteLength > FILE_LIMIT_SIZE) {

            bw.flush();

            // 文件数递增
            fileNum++;
            // 小文件的字节大小重置为0
            smallFileByteLength = 0;

            smallFile = new File(dirStr + fileNum + ".txt");
            fos = new FileOutputStream(smallFile);
            bw = new BufferedWriter(new OutputStreamWriter(fos, "utf-8"));

        }

        // 避免代码错误生成非常多小文件
        if (fileNum > 20) {
            break;
        }

    }


    bw.flush();
    bw.close();

}

阅读全文 »

常见算法总结 - 二叉树篇

本文总结了常见高频的关于二叉树的算法考察。

1.计算一个给定二叉树的叶子节点数目。

可以采用递归的方式进行累加

public static int calculateTreeNodeNumber(TreeNode treeNode) {

        if (treeNode == null) {
            return 0;
        }

        return calculateTreeNodeNumber(treeNode.left) + calculateTreeNodeNumber(treeNode.right) + 1;

}

2.计算二叉树的深度。

跟上题一样采用递归的方式,但需返回左右子树中较深的深度。

public static int getTreeDepth(TreeNode tree) {

        if (tree == null) {
            return 0;
        }

        int left = getTreeDepth(tree.left);
        int right = getTreeDepth(tree.right);

        return left >= right ? left + 1 : right + 1;
}

阅读全文 »

常见算法总结 - 排序篇

本文总结了常见高频的关于排序的算法考察。

1.冒泡排序

冒泡排序的思想是元素两两比较,将较大或者较小的元素往一端进行移动

 public static void bubble(int[] array) {

        for (int i = 0; i < array.length - 1; i++) {

            for (int j = 0; j + 1 < array.length - i; j++) {

                if (array[j] > array[j + 1]) {

                    int tmp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tmp;

                }

            }

        }

}

阅读全文 »

常见算法总结 - 链表篇

本文总结了常见高频的关于链表的算法考察。

1.如何找到链表的中间元素?

我们可以采用快慢指针的思想,使用步长为1的慢指针和步长为2的快指针,当快指针抵达链表末尾时,此时慢指针指向的即为中点位置。


public static LinkNode findMiddleByPointer(LinkNode node) {

    LinkNode slow = node;
    LinkNode fast = node;
    // 检测快指针是否可以安全移动
    while (fast.next != null && fast.next.next != null) {

        slow = slow.next;
        fast = fast.next.next;

    }

    return slow;

}

我们还可以采用递归的方式,当递归到最末尾的时候,我们已经能知道链表的长度,此时当递归回去的时候,判断当前递归层级等于链表长度一半的时候,即为链表的重点。

public static void findMiddleByRecursion(LinkNode node, int recursionIndex) {

        if (node.next != null) {
            findMiddleByRecursion(node.next, recursionIndex + 1);
        } else {
            middleIndex = recursionIndex % 2 == 0 ? recursionIndex / 2 : recursionIndex / 2 + 1;
        }

        if (middleIndex == recursionIndex) {
            System.out.println(node.value);
        }

        return;

    }
阅读全文 »

常见算法总结 - 数组篇

1.给定一个数值在1-100的整数数组,请找到其中缺少的数字。

找到丢失的数字 利用byte数组的1或0标记该数字是否被删除,例如byte数组下标为0的数值为1的话,代表数字1存在

public static void findMissNumber1(int[] ints) {
        // 声明一个byte数组
        byte[] isExist = new byte[100];
        for (int i = 0; i < ints.length; i++) {
            // 由于数值比下标大1, 0位置其实代表的是数字1
            isExist[ints[i] - 1] = 1;

        }
        for (int i = 0; i < isExist.length; i++) {
            if (isExist[i] == 0) {
                System.out.println("删除的数字是:" + ++i );
            }
        }
}

我们可以利用1-100的总和为5050,我们依次减掉数据内的所有值,得到的差值即为删除的值

public static void findMissNumber2(int[] ints) {
        int sum = 5050;
        for (int i = 0; i < ints.length; i++) {
            sum -= ints[i];
        }
        System.out.println("删除的数字:" + sum);
}

2.从数组中找出给定目标数字的两数组合。例如数组为{2, 3, 5, 7, 8, 9, 11, 14, 18},给定数字给17,那么数组内的3+14=17。

先利用Set存储对应的数字,然后再遍历数组,假设遍历到数字3的时候,检查set中是否存在(17-3)=14这个数字,如果存在的话,即存在这个组合。

public static void findPairNumber(int[] arrays, int target) {

        Set<Integer> existIntegers = new HashSet<>();
        for (int i = 0; i < arrays.length; i++) {
            existIntegers.add(arrays[i]);
        }
        for (int i = 0; i < arrays.length; i++) {
            if (existIntegers.contains(target - arrays[i])) {
                System.out.println("找到对应的数字组合:" + arrays[i] + "和" + (target - arrays[i]));
                // 去除掉已使用过的数字
                existIntegers.remove(arrays[i]);
            }
        }
    }

3.将数组进行反转。

只需要将数组按中间位置为对称轴进行位置交换即可

public static void reverseArray(int[] arrays) {

    for (int i = 0; i < arrays.length/2; i++) {

        int tmp = arrays[i];
        arrays[i] = arrays[arrays.length -1 - i];
        arrays[arrays.length -1 - i] = tmp;

    }

}
阅读全文 »

sysbench压测MySQL性能及优化 有更新!

sysbench安装流程

下载
wget https://github.com/akopytov/sysbench/archive/master.zip
unzip安装
yum install unzip
解压
unzip master.zip
安装相关依赖
yum -y install  make automake libtool pkgconfig libaio-devel vim-common
yum -y install mysql-devel 
编译

进入之前解压后的文件夹

./autogen.sh
#如果不是yum安装的原文件地址的话,需要添加参数改
./configure 
make
make install
阅读全文 »

RR级别下update操作的是快照读还是当前读? 有更新!

我们知道在RR级别下,重复的select操作,读取的值都会是一致的。即便在两次select操作的中间,有一个事务B修改了值,但是在事务A中select读取的值还是一致的。

那么如果是update操作呢?之前在网上看到一篇博客说RR级别下,CAS操作是没有意义的。因为version值在一个事务中都是一致不变的。于是我有了疑惑打算自己来验证一下。

验证想法

RR级别下update操作的是快照读还是当前读?

准备数据

准备了以下简单的表数据结构。

sidnamesexversion
1zhangsan00
2lisi10
阅读全文 »

Hutool - 小而全的Java开发工具库推荐

Hutool简介

Hutool是一款小而全的开源开发工具类库,在github上拥有将近一万九的star,基本上你能想到的开发当中常需要用到的小轮子,基本上都有具备。学习一下hutool工具包可以避免我们在平常开发中重复造轮子。这款hutool开源库,更新频率快,jar包小仅1.5Mb。对比其他同款类型的基础工具类库来说,是一大优势。因为其他同款类型的基础工具类库多多少少都有基于apache commons做了一些封装。

对于很多小型公司来说,公司内部并没有完善的基础工具类库,使用hutool可以节省了开发人员对项目中公用类和公用工具方法的封装时间,使开发专注于业务同时可以最大限度的避免封装不完善带来的bug。

hutool github地址

Hutool主要组件

模块介绍
hutool-aopJDK动态代理封装,提供非IOC下的切面支持
hutool-bloomFilter布隆过滤,提供一些Hash算法的布隆过滤
hutool-cache简单缓存实现
hutool-core核心,包括Bean操作、日期、各种Util等
hutool-cron定时任务模块,提供类Crontab表达式的定时任务
hutool-crypto加密解密模块,提供对称、非对称和摘要算法封装
hutool-dbJDBC封装后的数据操作,基于ActiveRecord思想
hutool-dfa基于DFA模型的多关键字查找
hutool-extra扩展模块,对第三方封装(模板引擎、邮件、Servlet、二维码、Emoji、FTP、分词等)
hutool-http基于HttpUrlConnection的Http客户端封装
hutool-log自动识别日志实现的日志门面
hutool-script脚本执行封装,例如Javascript
hutool-setting功能更强大的Setting配置文件和Properties封装
hutool-system系统参数调用封装(JVM信息等)
hutool-jsonJSON实现
hutool-captcha图片验证码实现
hutool-poi针对POI中Excel的封装
hutool-socket基于Java的NIO和AIO的Socket封装

hutool库的工具类非常全,一篇文章难以概括。以下就列举开发中常用到的工具类。

阅读全文 »