笔记

开发实战及解决方案 笔记

1. 系统简介

系统架构

系统架构

服务间关系

服务关系

2. 单点登录及第三方登录解决方案

token生成流程

token生成流程

微信登录流程

微信登录流程

3. 第三方支付

支付宝

https://opendocs.alipay.com/apis/api_1/alipay.trade.precreate

微信支付

https://pay.weixin.qq.com/wiki/doc/apiv3/wxpay/pages/Overview.shtml

4. 秒杀

后台发布秒杀活动课程信息

后台发布秒杀活动课程信息

前端用户抢购课程

前端用户抢购课程

超时未支付流程

超时未支付流程

5. 分布式事务解决方案 Seata

Seata 是一款开源的分布式事务解决方案,致力于提供高性能和简单易用的分布式事务服

务。 Seata 将为用户提供了 AT、TCC、SAGA 和 XA 事务模式,为用户打造一站式的分布式解决方案。

官方文档地址:https://seata.io/zh-cn/index.html

Seata 下载地址:https://seata.io/zh-cn/docs/ops/deploy-guide-beginner.html

视频加密流程

image-20200918170348950

作业

作业

1 、 什么是CAS

CAS是英文单词CompareAndSwap的缩写,中文意思是:比较并替换。CAS需要有3个操作数:内存地址V,旧的预期值A,即将要更新的目标值B。CAS指令执行时,当且仅当内存地址V的值与预期值A相等时,将内存地址V的值修改为B,否则就什么都不做。整个比较并替换的操作是一个原子操作。CAS是乐观锁技术,当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值,而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试

2、CyclicBarrier和CountDownLatch区别

​ CyclicBarrier是一种同步机制允许一组线程相互等待,等到所有线程都到达一个屏障点才退出await方法,它没有直接实现AQS而是借助ReentrantLock来实现的同步机制。它是可循环使用的,而CountDownLatch是一次性的,另外它体现的语义也跟CountDownLatch不同,CountDownLatch减少计数到达条件采用的是release方式,而CyclicBarrier走向屏障点(await)采用的是Acquire方式,Acquire是会阻塞的,这也实现了CyclicBarrier的另外一个特点,只要有一个线程中断那么屏障点就被打破,所有线程都将被唤醒(CyclicBarrier自己负责这部分实现,不是由AQS调度的),这样也避免了因为一个线程中断引起永远不能到达屏障点而导致其他线程一直等待。屏障点被打破的CyclicBarrier将不可再使用(会抛出BrokenBarrierException)除非执行reset操作

3、volatile关键字的作用

作用:保证被修饰变量的内存可见性,用volatile修饰的变量,线程在每次使用变量的时候,都会读取变量修改后的最新的值。

4 、如何正确的使用wait()?使用if还是while?

wait() 方法应该在循环调用,因为当线程获取到 CPU 开始执行的时候,其他条件可能还没有满足,所以在处理前,循环检测条件是否满足会更好

5 、为什么wait、nofity和nofityAll这些方法不放在Thread类当中

JAVA提供的锁是对象级的而不是线程级的,每个对象都有锁,通过线程获得。如果线程需要等待某些锁那么调用对象中的wait()方法就有意义了。如果wait()方法定义在Thread类中,线程正在等待的是哪个锁就不明显了。简单的说,由于wait,notify和notifyAll都是锁级别的操作,所以把他们定义在Object类中因为锁属于对象。

6、synchronized和ReentrantLock的区别

相似点: 这两种同步方式有很多相似之处,它们都是加锁方式同步,而且都是阻塞式的同步,也就是说当如果一个线程获得了对象锁,进入了同步块,其他访问该同步块的线程都必须阻塞在同步块外面等待,而进行线程阻塞和唤醒的代价是比较高的(操作系统需要在用户态与内核态之间来回切换,代价很高,不过可以通过对锁优化进行改善)。 功能区别: 这两种方式最大区别就是对于Synchronized来说,它是java语言的关键字,是原生语法层面的互斥,需要jvm实现。而ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成 便利性:很明显Synchronized的使用比较方便简洁,并且由编译器去保证锁的加锁和释放,而ReenTrantLock需要手工声明来加锁和释放锁,为了避免忘记手工释放锁造成死锁,所以最好在finally中声明释放锁。 锁的细粒度和灵活度:很明显ReenTrantLock优于Synchronized 性能的区别: 在Synchronized优化以前,synchronized的性能是比ReenTrantLock差很多的,但是自从Synchronized引入了偏向锁,轻量级锁(自旋锁)后,两者的性能就差不多了,在两种方法都可用的情况下,官方甚至建议使用synchronized,其实synchronized的优化我感觉就借鉴了ReenTrantLock中的CAS技术。都是试图在用户态就把加锁问题解决,避免进入内核态的线程阻塞。

7、什么是AQS

AQS,即AbstractQueuedSynchronizer, 队列同步器,它是Java并发用来构建锁和其他同步组件的基础框架。AQS是一个抽象类,主是是以继承的方式使用。AQS本身是没有实现任何同步接口的,它仅仅只是定义了同步状态的获取和释放的方法来供自定义的同步组件的使用。

8、什么是Java内存模型

https://www.yuque.com/docs/share/1075cf31-8b7d-42c2-803d-e3307aca851f?# 《Java内存模型》

9、什么是自旋

是指当一个线程在获取锁的时候,如果锁已经被其它线程获取,那么该线程将循环等待,然后不断的判断锁是否能够被成功获取,直到获取到锁才会退出循环。

10、Java编程写一个会导致死锁的程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
public class DeadLock implements Runnable {
private int flag;

public DeadLock(int flag) {
this.flag = flag;
}

static Object lock1 = new Object();
static Object lock2 = new Object();


public void run() {

if (flag == 0) {
synchronized (lock1) {
try {
System.out.println("线程:" + Thread.currentThread().getName() + "已获得锁" + lock1);
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程:" + Thread.currentThread().getName() + "等待获得锁" + lock2);
synchronized (lock2) {
System.out.println("线程:" + Thread.currentThread().getName() + "已获得锁" + lock2);
}
}
}
if (flag == 1) {

synchronized (lock2) {
try {
System.out.println("线程:" + Thread.currentThread().getName() + "已获得锁" + lock2);
Thread.sleep(500);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println("线程:" + Thread.currentThread().getName() + "等待获得锁" + lock1);
synchronized (lock1) {
System.out.println("线程:" + Thread.currentThread().getName() + "已获得锁" + lock1);
}
}
}
}

public static void main(String[] args) {
DeadLock test1 = new DeadLock(0);
DeadLock test2 = new DeadLock(1);
Thread thread1 = new Thread(test1);
Thread thread2 = new Thread(test2);
thread1.start();
thread2.start();
}
}

并发编程

​ 并发编程

AQS(AbstractQueuedSynchronizer)翻译为抽象队列同步器,是除Synchronized关键字外java自带的锁机制。

AQS使用一个int类型变量state来表示线程要竞争的资源,state的值即为可获取的资源数,当一个线程尝试获取锁时,会使用CAS方式去尝试改变state的值,如果改变成功,即获取了锁。CAS的实现是使用了Unsafe类底下的一系列compareAndSet*方法,这些方法调用了JAVA的native方法,可以认为是系统底层支持的原子操作.

数据结构与算法 学习笔记

​ 数据结构与算法 学习笔记

概念

数据结构是计算机存储和组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元素的集合。

常见的数据结构

image-20210408115710630

算法

概念

算法是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令,算法代表着用系统的方法描述解决问题的策略机制。

算法是一种解决特定问题的思路。

常见的算法

image-20210408133918634

算法复杂度

我们采用时间复杂度和空间复杂度来计算

时间复杂度

T(n)=O(f(n))

空间复杂度

空间复杂度全称是渐进空间复杂度,表示算法的存储空间与数据规模之间的增长关系

比如将一个数组拷贝到另一个数组中,就是相当于空间扩大了一倍:T(n)=O(2n),忽略系数即为O(n)

线性表

线性表(Linear List)就是数据排成像一条线一样的结构,数据只有前后两个方向

数组(Array)是有限个相同类型的变量所组成的有序集合,数组中的每一个变量被称为元素。数组是最为简单、最为常用的数据结构

应用

数组是基础的数据结构,应用太广泛了,ArrayList、Redis、消息队列等等。

链表(linked list)是一种在物理上非连续、非顺序的数据结构,由若干节点(node)所组成。

链表中数据元素的逻辑顺序是通过链表中的指针链接次序实现的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。每个结包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。(百度百科)

常见的链表包括:单链表、双向链表、循环链表

image-20210408134425525

数组和链表是线性数据存储的物理存储结构:即顺序存储和链式存储。

栈和队列都属于线性数据的逻辑存储结构

image-20210408134511941

(stack)是一种线性数据结构,栈中的元素只能先入后出(First In Last Out,简称FILO)。

最早进入的元素存放的位置叫作栈底(bottom),最后进入的元素存放的位置叫作栈顶 (top)。

队列

队列(queue)是一种线性数据结构,队列中的元素只能先入先出(First In First Out,简称 FIFO)。队列的出口端叫作队头(front),队列的入口端叫作队尾(rear)。

散列表

散列表也叫作哈希表(hash table),这种数据结构提供了键(Key)和值(Value)的映射关系。只要

给出一个Key,就可以高效查找到它所匹配的Value,时间复杂度接近于O(1)。

存储原理

哈希函数

散列表在本质上也是一个数组 散列表的Key则是以字符串类型为主的通过hash函数把Key和数组下标进行转换

作用是把任意长度的输入通过散列算法转换成固定类型、固定长度的散列值。

递归,去的过程叫”递”,回来的过程叫”归

递归三要素

  • 递归结束条件

  • 函数的功能

    这个函数要干什么,打印,计算

  • 函数的等价关系式

    递归公式,一般是每次执行之间,或者与个数之间的逻辑关系

二分查找

二分查找(Binary Search)算法,也叫折半查找算法

有很多数据的逻辑关系并不是线性关系,在实际场景中,常常存在着一对多,甚至是多对多的情况。家谱

image-20210408135241370

二叉树

二叉树(binary tree)是树的一种特殊形式。二叉,顾名思义,这种树的每个节点最多有2个孩子节点。注意,这里是最多有2个,也可能只有1个,或者没有孩子节点

二叉查找树

二叉查找树(binary search tree),二叉查找树在二叉树的基础上增加了以下几个条件

如果左子树不为空,则左子树上所有节点的值均小于根节点的值

如果右子树不为空,则右子树上所有节点的值均大于根节点的值

左、右子树也都是二叉查找树

广度优先遍历(BFS,Breadth First Search)

也叫层序遍历,顾名思义,就是二叉树按照从根节点到叶子节点的层次关系,一层一层横向遍历各个节点。

深度优先搜索(DFS Depth First Search)

深度优先搜索,从起点出发,从规定的方向中选择其中一个不断地向前走,直到无法继续为止,然后尝

试另外一种方向,直到最后走到终点。就像走迷宫一样,尽量往深处走。

二叉查找树的插入和查找时间复杂度为:O(logn)

极端情况下二叉查找树退化成链表,时间复杂度为O(n),所以需要平衡二叉查找树。

红黑树

红黑树就是一种自平衡的二叉查找树

除了二叉查找树(BST)的特征外,还有以下特征:

每个节点要么是黑色,要么是红色

根节点是黑色

每个叶子节点都是黑色的空结点(NIL结点)(为了简单期间,一般会省略该节点)

如果一个节点是红色的,则它的子节点必须是黑色的(父子不能同为红)

从任一结点到其每个叶子的所有路径都包含相同数目的黑色结点(平衡的关键)

新插入节点默认为红色,插入后需要校验红黑树是否符合规则,不符合则需要进行平衡

多路查找树

*多路查找树(muitl-way search tree),其每一个节点的孩子数可以多于两个,且每一个节点处可以存储多个元素 *

B树(BalanceTree)是对二叉查找树的改进。它的设计思想是,将相关数据尽量集中在一起,以便一

次读取多个数据,减少硬盘操作次数

image-20210408140120320

B+树是B-树的变体,也是一种多路搜索树,其定义基本与B树相同,它的自身特征是:

非叶子结点的子树指针与关键字个数相同

非叶子结点的子树指针P[i],指向关键字值属于[K[i], K[i+1])的子树

所有关键字都在叶子结点出现

为所有叶子结点增加一个链指针

image-20210408140134258

典型应用

MySQL索引B+Tree

B树是为了磁盘或其它存储设备而设计的一种多叉(下面你会看到,相对于二叉,B树每个内结点有多个

分支,即多叉)平衡查找树。 多叉平衡

B树的高度一般都是在2-4这个高度,树的高度直接影响IO读写的次数。

如果是三层树结构—支撑的数据可以达到20G,如果是四层树结构—支撑的数据可以达到几十T

B和B+的区别

B树和B+树的最大区别在于非叶子节点是否存储数据的问题。

二叉堆

二叉堆本质上是一种完全二叉树,它分为两个类型

大顶堆(最大堆)

最大堆的任何一个父节点的值,都大于或等于它左、右孩子节点的值

小顶堆(最小堆)

最小堆的任何一个父节点的值,都小于或等于它左、右孩子节点的值

算法思维

贪婪算法(Greedy)的定义:是一种在每一步选中都采取在当前状态下最好或最优的选择,从而希望

导致结果是全局最好或最优的算法

贪婪算法:当下做局部最优判断,不能回退

经典问题

部分背包问题

适用场景

针对一组数据,我们定义了限制值和期望值,希望从中选出几个数据,在满足限制值的情况下,期望值

最大。

分治算法

分治算法(divide and conquer)的核心思想其实就是四个字,分而治之 ,也就是将原问题划分成 n

个规模较小,并且结构与原问题相似的子问题,递归地解决这些子问题,然后再合并其结果,就得到原

问题的解。

关于分治和递归的区别

分治算法是一种处理问题的思想,递归是一种编程技巧

经典问题

字符串转大写

回溯算法

回溯算法实际上一个类似枚举的深度优先搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发

现已不满足求解条件时,就“回溯”返回(也就是递归返回),尝试别的路径

经典问题 N皇后问题

动态规划

动态规划(Dynamic Programming),是一种分阶段求解的方法。

动态规划算法是通过拆分问题,定义问题状态和状态之间的关系,使得问题能够以递推(或者说分治)

的方式去解决。

动态规划中有三个重要概念:

  • 最优子结构

  • 边界

  • 状态转移公式(递推方程)dp方程

经典问题 01 背包问题

k8s

​ Kubernetes 学习笔记

常用命令

1
2
3
4
5
6
7
8
9
查看default命名空间下的pods
kubectl get pods
查看kube-system命名空间下的pods
kubectl get pods -n kube-system
查看所有命名空间下的pods
kubectl get pod --all-namespaces
kubectl get pod -A
以纯文本输出格式列出所有pod ,并包含附加信息(如节点名)
kubectl get pods -o wide

运行pod

1
2
3
4
在default命名空间中创建一个pod副本的deployment
kubectl run tomcat9-test --image=tomcat:9.0.20-jre-alpine --port=8080
kubectl get pod
kubectl get pod -o wide

扩容

1
2
3
kubectl scale --replicas=3 deployment/tomcat9-test
kubectl get deployment
kubectl get deployment -o wide

创建服务

1
2
3
kubectl expose deployment tomcat9-test --name=tomcat9-svc --port=8888 --target-port=8080 --protocol=TCP --type=NodePort
kubectl get svc
kubectl get svc -o wide

delete 命令

1
2
3
kubectl delete -f pod.yaml 
删除所有 pod,包括未初始化的 pod
kubectl delete pods --all

进入容器

1
kubectl exec -ti <pod-name> /bin/bash

logs命令

1
2
3
4
# 从 pod 返回日志快照
kubectl logs <pod-name>
# 从 pod <pod-name> 开始流式传输日志。这类似于 'tail -f' Linux 命令。
kubectl logs -f <pod-name>

格式化输出

1
2
将pod信息格式化输出到一个yaml文件 
kubectl get pod web-pod-13je7 -o yaml

强制删除pod

1
2
强制删除一个pod 
--force --grace-period=0

Docker学习笔记

Docker学习笔记

当人们说“Docker”时,他们通常是指 Docker Engine,它是一个客户端 - 服务器应用程序,由 Docker守护进程、一个REST API指定与守护进程交互的接口、和一个命令行接口(CLI)与守护进程通信(通过封装REST API)。Docker Engine 从 CLI 中接受docker 命令,例如 docker run 、docker ps 来列出正在运行的容器、docker images 来列出镜像,等等。

docker 基本组成

docker主机(Host):安装了Docker程序的机器(Docker直接安装在操作系统之上);

docker仓库(Registry):用来保存各种打包好的软件镜像;仓库分为公有仓库和私有仓库。(很类似maven)

docker镜像(Images):软件打包好的镜像;放在docker仓库中;

docker容器(Container):镜像启动后的实例称为一个容器;容器是独立运行的一个或一组应用

docker 与操作系统比较

docker是一种轻量级的虚拟化方式

image-20210318150849177

Docker常用命令

image-20210318151000222

images命令

1
2
docker images 
docker image ls

save命令

1
2
3
4
mkdir -p /data 
cd /data
docker save tomcat:9.0.20-jre8-alpine -o tomcat9.tar
docker save tomcat:9.0.20-jre8-slim > tomcat9.slim.tar

inspect命令

  • 通过 docker inspect 命令,我们可以获取镜像的详细信息,其中,包括创建者,各层的数字摘要等。
1
2
docker inspect tomcat:9.0.20-jre8-alpine
docker inspect -f {{".Size"}} tomcat:9.0.20-jre8-alpine

history命令

  • 从前面的命令中,我们了解到,一个镜像是由多个层组成的,那么,我们要如何知道各个层的具体内容呢?

通过 docker history命令,可以列出各个层的创建信息,例如:查看 tomcat:9.0.20-jre8-alpine的各层信息

1
docker history tomcat:9.0.20-jre8-alpine

tag命令

  • 标记本地镜像,将其归入某一仓库
1
docker tag tomcat:9.0.20-jre8-alpine lagou/tomcat:9

rmi命令

常用参数

  • -f, -force : 强制删除镜像,即便有容器引用该镜像;
  • -no-prune : 不要删除未带标签的父镜像;
1
2
docker rmi tomcat:9.0.20-jre8-alpine 
docker image rm tomcat:9.0.20-jre8-alpine

清理镜像

我们在使用 Docker 一段时间后,系统一般都会残存一些临时的、没有被使用的镜像文件,可以通过以下命令进行清理。执行完命令后,还是告诉我们释放了多少存储空间!

1
docker image prune

Docker容器(container)

容器是镜像的运行时实例

image-20210318151857629

新建并启动容器

1
docker run [OPTIONS] IMAGE [COMMAND] [ARG...]
1
docker run -it --rm -p 8080:8080 tomcat:9.0.20-jre8-alpine

docker run命令常用参数比较多,这里仅仅列出开发岗常用参数,请小伙伴们自行查找资料获得更多参数信息

-d, –detach=false: 后台运行容器,并返回容器ID

-i, –interactive=false: 以交互模式运行容器,通常与 -t 同时使用

-P, –publish-all=false: 随机端口映射,容器内部端口随机映射到主机的端口。不推荐各位小伙伴使用该参数

-p, –publish=[]: 指定端口映射,格式为:主机(宿主)端口容器端口,推荐各位小伙伴们使用**

-t, –tty=false: 为容器重新分配一个伪输入终端,通常与 -i 同时使用

–name=”nginx-lb”: 为容器指定一个名称

-h , –hostname=”laosiji”: 指定容器的hostname

-e , –env=[]: 设置环境变量,容器中可以使用该环境变量

–net=”bridge”: 指定容器的网络连接类型,支持 bridge/host/none/container: 四种类型

–link=[]: 添加链接到另一个容器;不推荐各位小伙伴使用该参数

-v, –volume : 绑定一个卷

–privileged=false: 指定容器是否为特权容器,特权容器拥有所有的capabilities

–restart=no:指定容器停止后的重启策略

no:容器退出时不重启

on-failure:容器故障退出(返回值非零)时重启

always:容器退出时总是重启,推荐各位小伙伴们使用

–rm=false: 指定容器停止后自动删除容器,不能以docker run -d启动的容器

容器日志

1
docker logs [OPTIONS] CONTAINER

-f : 跟踪日志输出

–tail :仅列出最新N条容器日志

删除容器

docker rm 删除一个或多个容器。docker rm命令只能删除处于终止或退出状态的容器,并不能删除还处于运行状态容器

-f :通过 SIGKILL 信号强制删除一个运行中的容器。

-l :移除容器间的网络连接,而非容器本身。

-v :删除与容器关联的卷。

列出容器

docker ps [OPTIONS]

1
2
3
4
5
docker run -itd --name tomcat9 -p 8080:8080 tomcat:9.0.20-jre8-alpine 
查看运行中的容器
docker ps tomcat9
查看所有容器
docker ps -a tomcat9

启动、重启、终止容器

docker start :启动一个或多个已经被停止的容器

docker stop :停止一个运行中的容器

docker restart :重启容器

进入容器

1
docker exec [OPTIONS] CONTAINER COMMAND [ARG...]
1
2
3
4
5
6
有bash命令的linux系统:例如centos
docker run -it --name tomcat9.1 -p 8080:8080 tomcat:9.0.20-jre8-slim
docker exec -it tomcat9.1 /bin/bash
没有bash命令的linux系统:例如alpine系统
docker run -it --name tomcat9.2 -p 8081:8080 tomcat:9.0.20-jre8-alpine
docker exec -it tomcat9.2 sh

查看容器

docker inspect : 获取容器/镜像的元数据。

语法

1
docker inspect [OPTIONS] NAME|ID [NAME|ID...]
1
2
docker run -it --name tomcat9 -p 8081:8080 tomcat:9.0.20-jre8-alpine 
docker inspect tomcat9

常用参数

-f :指定返回值的模板文件。

-s :显示总的文件大小。

–type :为指定类型返回JSON。

image-20210318153201331

ElasticSearch学习笔记

ElasticSearch学习笔记
  • 概念

    Elaticsearch简称为ES,是一个开源的可扩展的分布式的全文检索引擎,它可以近乎实时的存储、检索数据。本身扩展性很好,可扩展到上百台服务器,处理PB级别的数据。ES使用Java开发并使用Lucene作为其核心来实现索引和搜索的功能,但是它通过简单的RestfulAPIjavaAPI来隐藏Lucene的复杂性,从而让全文搜索变得简单。

  • 功能

    1. 分布式的搜索引擎

      分布式:Elasticsearch自动将海量数据分散到多台服务器上去存储和检索

      搜索:百度、谷歌,站内搜索

​ 2. 全文检索

​ 提供模糊搜索等自动度很高的查询方式,并进行相关性排名,高亮等功能

​ 3. 数据分析引擎(分组聚合)

​ 电商网站,最近一周笔记本电脑这种商品销量排名top10的商家有哪些?新闻网站,最近1个月访问量排名top3的新闻板块是哪些.

​ 4 . 对海量数据进行近实时的处理

​ 海量数据的处理:因为是分布式架构,Elasticsearch可以采用大量的服务器去存储和检索数据,自然而然就可以实现海量数据的处理近实时:Elasticsearch可以实现秒级别的数据搜索和分析.

​ 使用实例

创建索引

1
2
3
4
5
6
PUT my_index
{
"settings": {
"属性名""属性值"
}
}

判断索引是否存在

1
HEAD /my_index

查看索引

1
GET /my_index

批量查看索引

1
GET /索引名称1,索引名称2

查看所有索引

1
GET _all
1
GET /_cat/indices?v

删除索引库

1
DELETE /my_indx

字段映射

1
2
3
4
5
6
7
8
9
10
11
PUT /索引库名/_mapping
{
"properties":{
"字段名"{
"type":"类型",
"index":true,
"store":true,
"analyzer":"分词器"
}
}
}

eg:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
PUT /lagou-company-index
PUT /lagou-company-index/_mapping
{
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word"
},
"job": {
"type": "text",
"analyzer": "ik_max_word"
},
"logo": {
"type": "keyword",
"index": false
},
"payment": {
"type": "float"
}
}
}

文档的增删改查及局部更新

文档,即索引库中的数据,会根据规则创建索引,将来用于搜索。可以类比做数据库中的一行数据

语法

1
2
3
4
POST /索引名称/_doc 
{
"field":"value"
}
1
2
3
4
5
6
7
POST /lagou-company-index/_doc/1
{
"name":"百度",
"job":"小度用户运营经理",
"payment":"30000",
"logo":"http://www.lgstatic.com/thubnail_120x120/i/image/M00/21/3E/CgpFT1kVdzeAJNbUAABJB7x9sm8374.png"
}

查看单个文档

1
GET /索引名称/_doc/{id}

查看所有文档

1
2
3
4
5
6
7
POST /索引名称/_search 
{
"query":{
"match_all": {
}
}
}

更新文档

局部更新

1
2
3
4
5
6
POST /lagou-company-index/_update/1
{
"doc":{
"logo":"1111"
}
}

全部更新

​ 新增请求 改为PUT 就是修改了

​ DSL语句

1
2
3
4
5
6
POST /lagou-company-index/_search
{
"query": {
"match_all": {}
}
}
1
2
3
4
5
6
7
8
POST /lagou-company-index/_search
{
"query": {
"match": {
"name": "百度"
}
}
}

match 类型查询,会把查询条件进行分词,然后进行查询,多个词条之间是or的关系

短语搜索 (match phrase query)

match_phrase 查询用来对一个字段进行短语查询,可以指定 analyzer、slop移动因子

1
2
3
4
5
6
7
8
9
10
11
POST /lagou-company-index/_search
{
"query": {
"match_phrase": {
"name":{
"query": "百 12",
"slop": 2
}
}
}
}

query_string 查询

Query String Query提供了无需指定某字段而对文档全文进行匹配查询的一个高级查询,同时可以指定在哪些字段上进行匹配。

1
2
3
4
5
6
7
8
GET /lagou-company-index/_search
{
"query": {
"query_string": {
"query": "30000"
}
}
}

词条级搜索 (term-level queries)

可以使用term-level queries根据结构化数据中的精确值查找文档。结构化数据的值包括日期范围、IP地址、价格或产品ID。

与全文查询不同,term-level queries不分析搜索词。相反,词条与存储在字段级别中的术语完全匹配。

1
2
3
4
5
6
7
8
9
10
POST /lagou-company-index/_search
{
"query": {
"term": {
"name": {
"value": "12"
}
}
}
}

基于RocketMQ设计秒杀。

​ 基于RocketMQ设计秒杀作业

整体思路:

1 使用redis 进行获取锁

2 获取锁后 调用RocketMQ 发送订单消息

​ - 使用redis 进行订单数量的累加 同时 redis 记录订单id

3 rocketmq 收到下单消息后 进行下单操作 等待用户支付 。

4 向RocketMQ 发送一条延时订单 检查的消息

5 延时消息到期后

​ 检查订单状态 如果支付 不进行有效订单的数量的操作

​ 未完成支付 有效订单数量减少

步骤

  • 首先 先新建springboot 项目 整合RockertMQ +Redis

image-20210303135500684

image-20210303135630504

​ redis 本地 正常 下单请求会有 orderSize 变成100 同时 会有100条订单记录

​ 使用线程池默认并发500下单 操作

image-20210303135728017

​ 本地访问 http://localhost:8080/order

image-20210303135913602

image-20210303140229125

​ 等待超时队列到期 不支付 订单达到100 清除 未支付的订单 数量

image-20210303140708775

​ 可以看到 有效订单数量减少为0

image-20210303140527850

此时 用户可以继续下单操作

image-20210303140818437

这样就保证了库存不超卖的情况。