一、SpringWebFlux介绍

可以直接去官网看看:https://docs.spring.io/spring-framework/docs/current/reference/html/web-reactive.html

(1)是Spring5添加的新的模块,用于web开发的,功能与SpringMVC类似的,WebFlux使用的当前一种比较流行的响应式编程框架

(2)使用传统的web框架,比如SpringMVC,这些基于Servlet容器,WebFlux是一种异步非阻塞的框架,异步非阻塞框架在Servlet3.1以后才支持,核心是基于Reactor相关API实现的

(3)异步非阻塞:

  • 异步与同步

    针对调用者来说,调用者发送请求,如果等着对方回应之后才去做其他事情就是 同步;如果发送请求之后,不等对方回应就去做其他事情就是 异步

  • 非阻塞与阻塞

    针对被调用者而言,被调用者在收到请求之后,做完任务之后才给出反馈就是 阻塞;收到请求之后马上给出反馈然后再去做事情就是就是 非阻塞

(4)WebFlux的特点:

  • 1、非阻塞式:可以在有限的资源下,提高系统的吞吐量和伸缩性,以Reactor为基础实现函数式编程
  • 2、Spring5基于Java8,WebFlux使用Java8函数式编程的方式实现路由请求

(5)与SpringMVC比较

  • 1、上述两个框架都可以使用注解方式,都运行在Tomcat等容器中
  • 2、SpringMVC采用命令式编程,WebFlux采用异步式响应编程

网关使用异步式响应编程更好,因为网关需要处理更多的请求

二、响应式编程(Java实现)

(1)什么是响应式编程

简称RP(Reactive Programming)

响应式编程是一种 面向数据流 变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播。

根据数据或者数据流发生变化,相应的计算模型就会根据值的变化而变化,例如:电子表格程序就是响应式编程的一个例子。单元格可以包含字面值或类似”=B1+C1”的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化。

(2)Java8及其之前的版本

提供了 观察者模式的两个类: Observer Observable。即观察你关心的数据的变化,一旦出现变化,就发出通知。

直接上代码,代码中我们设置了改变并进行了通知:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class ObserverDemo extends Observable {
public static void main(String[] args) {
ObserverDemo observer = new ObserverDemo();
//添加观察者
observer.addObserver((o, arg) -> {
System.out.println("发生变化");
});
observer.addObserver((o, arg) -> {
System.out.println("手动改变观察者通知,准备改变");
});
//数据变化
observer.setChanged();
//通知
observer.notifyObservers();
}
}

(3)Java9及其之后的版本

使用 Flow实现,这里直接看下面代码:

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
54
55
56
57
58
59
60
61
62
63
64
65
66
67
//创建我自己的订阅者
class MySubscriber<T> implements Flow.Subscriber {
//发布者与订阅者之间的纽带
private Flow.Subscription subscription;
//订阅时会触发该问题
@Override
public void onSubscribe(Flow.Subscription subscription) {
this.subscription = subscription;
//开始请求数据
subscription.request(1);
}
//接收到数据是会触发该方法
@Override
public void onNext(Object item) {
System.out.println("获取到数据" + item);
//请求下一条数据
subscription.request(1);
}
//订阅出错时
@Override
public void onError(Throwable throwable) {
throwable.printStackTrace();
synchronized ("java") {
"java".notifyAll();
}
}
//订阅结束时触发该方法
@Override
public void onComplete() {
System.out.println("订阅结束时");
synchronized ("java") {
"java".notifyAll();
}
}
}
public class PubSubTest {
public static void main(String[] args) {
//创建一个SubmissionPublisher作为发布者
SubmissionPublisher<String> publisher = new SubmissionPublisher<>();
//创建订阅者
MySubscriber<String> subscriber = new MySubscriber<>();
//注册订阅者
publisher.subscribe(subscriber);
//发布几个数据项
System.out.println("开发发布数据...");
List.of("Java", "Go", "Erlang", "Swift", "Lua")
.forEach(im -> {
//提交数据
publisher.submit(im);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
//发布结束
publisher.close();
//发布结束之后,为了让线程不会死亡,暂停线程
synchronized ("java") {
try {
"java".wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

三、响应式编程(Reactor实现)

(1)规范框架

响应式编程操作中, Reactor是满足 Reactive规范框架

(2)核心类

Reactor有两个核心类,Mono Flux,这两个类实现接口 Publisher,提供丰富操作符。 Flux对象实现发布者,返回N个元素; Mono实现发布者,返回0或者一个元素

(3)三种信号

Flux Mono都是数据流的发布者,使用 Flux Mono都可以发出三中信号:元素值 错误信号 完成信号(错误信号与完成信号用于告诉订阅者数据流结束了,他俩都是终止信号,错误信号在终止数据流时会同时将错误信息传递给订阅者)

以下图片说明了两者的区别(Flux返回0个或者多个元素,Mono返回一个元素):

(4)代码演示

接下来咱们直接在代码上来实现:

  • 引入依赖
1
2
3
4
5
<dependency>
<groupId>io.projectreactor</groupId>
<artifactId>reactor-core</artifactId>
<version>3.4.0</version>
</dependency>
  • 代码编写
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestReactor {
public static void main(String[] args) {
//just方法直接声明
Flux.just(1,2,3,4);
Mono.just(1);
//其他方法进行声明
Integer[] array = {1, 2, 3, 4};
Flux.fromArray(array);

List<Integer> list = Arrays.asList(array);
Flux.fromIterable(list);

Stream<Integer> stream = list.stream();
Flux.fromStream(stream);
}
}

(5)三种信号的特点

  • 错误信号和完成信号都是终止信号,是不能共存的
  • 如果没有发送任何元素值,而是直接发送错误信号或者完成信号,表示的是空数据流
  • 如果没有错误信号,没有完成信号,表示的是无线信号流

(6)订阅

调用 just或者其他方法只是声明数据流,数据流并没有发出,只有进行订阅之后才会触发数据流,不订阅啥都不会发生

1
2
Flux.just(1,2,3,4).subscribe(System.out::println);
Mono.just(1).subscribe(System.out::println);

(7)操作符

对数据流进行一道道操作,成为操作符,比如工厂流水线

  • map

    将元素映射为新元素

  • flatMap

    将元素映射为流(将多个元素转成流,然后将多个流转成一个大流)

四、WebFlux执行流程和核心API

SpringWebFlux基于Reactor,默认使用的容器是Netty,Netty是高性能的NIO框架,异步非阻塞的框架

(1)Netty

  • NIO(非阻塞)
  • BIO(阻塞)

(2) SpringWebFlux执行过程和SpringMVC相似的

  • SpringWebFlux核心控制器 DispatchHandler,实现接口 WebHandler

  • 接口 WebHandler有一个方法:

    1
    2
    3
    public interface WebHandler {
    Mono<Void> handle(ServerWebExchange var1);
    }

(3)SpringWebFlux里面的DispatcherHandler,负责请求的处理

  • HandlerMapping:请求查询到处理的方法
  • HandlerAdapter:真正负责请求处理
  • HandlerResultHandler:响应结果处理

(4)SpringWebFlux函数式编程

SpringWebFlux实现函数式编程,有两个接口: RouterFunction(路由处理) HandlerFunction(处理函数)

五、SpringWebFLux(基于注解编程模型)

SpringWebFlux实现方式有两种: 注解编程模型 函数式编程模型

使用注解编程模型方式,和之前的 SpringMVC使用相似,只需要将相关依赖配置到项目中, SpringBoot自动配置相关运行容器,默认情况下使用Netty服务器

(1)创建SpringBoot工程,引入 WebFlux依赖

 依赖如下:

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
(2)配置启动端口号
1
server.port=8081

(3)创建包和相关类

  • 实体类

    1
    2
    3
    4
    5
    public class User {
    private String name;
    private String gender;
    private Integer age;
    }
  • 接口定义操作

    1
    2
    3
    4
    5
    6
    7
    8
    public interface UserService {
    //根据ID查询用户
    Mono<User> getUserById(int id);
    //查询所有用户
    Flux<User> getAllUser();
    //添加用户
    Mono<Void> saveUserInfo(Mono<User> user);
    }
  • 接口的实现类

    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
    @Service
    public class UserServiceImpl implements UserService {
    //创建map集合存储数据
    private final Map<Integer,User> users = new HashMap<>();

    //无参构造
    public UserServiceImpl() {
    this.users.put(1,new User("lucy","nan",20));
    this.users.put(2,new User("mary","nv",30));
    this.users.put(3,new User("jack","nv",50));
    }

    //根据id查询
    @Override
    public Mono<User> getUserById(int id) {
    return Mono.justOrEmpty(this.users.get(id));
    }

    //查询多个用户
    @Override
    public Flux<User> getAllUser() {
    return Flux.fromIterable(this.users.values());
    }

    //添加用户
    @Override
    public Mono<Void> saveUserInfo(Mono<User> userMono) {
    return userMono.doOnNext(person -> {
    //向map集合里面放值
    int id = users.size()+1;
    users.put(id,person);
    }).thenEmpty(Mono.empty());
    }
    }
  • 编写Controller层

    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
    @RestController
    public class UserController {

    //注入service
    @Autowired
    private UserService userService;

    //id查询
    @GetMapping("/user/{id}")
    public Mono<User> geetUserId(@PathVariable int id) {
    return userService.getUserById(id);
    }

    //查询所有
    @GetMapping("/user")
    public Flux<User> getUsers() {
    return userService.getAllUser();
    }

    //添加
    @PostMapping("/saveuser")
    public Mono<Void> saveUser(@RequestBody User user) {
    Mono<User> userMono = Mono.just(user);
    return userService.saveUserInfo(userMono);
    }
    }

    说明:

    • SpringMVC方式,同步阻塞的方式,基于 SpringMVC + Servlet + Tomcat
    • SpringWebFlux方式,异步非阻塞的方式,基于 SpringWebFlux + Reactor + Netty

六、SpringWebFLux(基于函数式编程模型)

  • 在使用函数式编程模型操作的时候,需要自己初始化服务器

  • 基于函数式编程模型的时候,有两个核心接口:

    RouterFunction(实现路由的功能) HandlerFunction(处理请求生成响应的函数)

    核心任务:定义两个函数式接口的实现并且启动需要的服务器

  • SpringWebFlux请求和响应不再是 ServletRequest ServletResponse

(1)创建Handler(具体实现方法)

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
public class UserHandler {
private final UserService userService;
public UserHandler(UserService userService) {
this.userService = userService;
}
//根据ID查询
public Mono<ServerResponse> getUserById(ServerRequest request) {
//获取id值
int userId = Integer.parseInt(request.pathVariable("id"));
//空值处理
Mono<ServerResponse> notFound = ServerResponse.notFound().build();
//调用Service方法得到数据
Mono<User> userMono = this.userService.getUserById(userId);
//将userMono进行转换返回,使用Reactor的操作符flatMap
return userMono.flatMap(person -> ServerResponse.ok().contentType(MediaType.APPLICATION_JSON)
.body(fromObject(person))
).switchIfEmpty(notFound);
}

//查询所有
public Mono<ServerResponse> getAllUsers() {
//调用Service得到结果
Flux<User> users = this.userService.getAllUser();
return ServerResponse.ok().contentType(MediaType.APPLICATION_JSON).body(users, User.class);
}

//添加
public Mono<ServerResponse> saveUser(ServerRequest request) {
//得到User对象
Mono<User> userMono = request.bodyToMono(User.class);
return ServerResponse.ok().build(this.userService.saveUserInfo(userMono));
}
}

(2)初始化服务器,编写Router

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Server {
//1、创建路由
public RouterFunction<ServerResponse> routingFunction() {
//创建Handler对象
UserService userService = new UserServiceImpl();
UserHandler handler = new UserHandler(userService);
//设置路由
return RouterFunctions.route(
GET("/users/{id}").and(accept(MediaType.APPLICATION_JSON)), handler::getUserById
).andRoute(
GET("/users").and(accept(MediaType.APPLICATION_JSON)), handler::getAllUsers
);
}
}

(3)创建服务器完成适配

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
public class Server {
//1、创建路由
public RouterFunction<ServerResponse> routingFunction() {
//创建Handler对象
UserService userService = new UserServiceImpl();
UserHandler handler = new UserHandler(userService);
//设置路由
return RouterFunctions.route(
GET("/users/{id}").and(accept(MediaType.APPLICATION_JSON)), handler::getUserById
).andRoute(
GET("/users").and(accept(MediaType.APPLICATION_JSON)), handler::getAllUsers
);
}

//2、创建服务器,完成适配
public void createReactorServer() {
//路由和handler适配
RouterFunction<ServerResponse> route = routingFunction();
HttpHandler httpHandler = toHttpHandler(route);
ReactorHttpHandlerAdapter adapter = new ReactorHttpHandlerAdapter(httpHandler);
//创建服务器
HttpServer httpServer = HttpServer.create();
httpServer.handle(adapter).bindNow();
}
}

(4)最终调用

1
2
3
4
5
6
public static void main(String[] args) throws IOException {
Server server = new Server();
server.createReactorServer();
System.out.println("enter to exit");
System.in.read();
}

(5)使用WebClient调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Client {
public static void main(String[] args) {
//调用服务器地址
WebClient webClient = WebClient.create("http://127.0.0.1:56264");
//根据id查询
String id = "1";
User user = webClient.get().uri("/users/{id}", id).accept(MediaType.APPLICATION_JSON).
retrieve().bodyToMono(User.class).block();
System.out.println(user.getName());
//查询所有
Flux<User> results = webClient.get().uri("/users").accept(MediaType.APPLICATION_JSON).
retrieve().bodyToFlux(User.class);
results.map(stu -> stu.getName()).buffer().doOnNext(System.out::println).blockFirst();
}
}

一、Vocabulary

1、cling

v.紧紧抓住

2、vacuous

3、millennial

二、Phrase

1、

2、

三、SpecificNoun

一、Vocabulary

1、furor

n.轰动,群情激愤,公愤

2、unambiguous

adj.不含糊的(去掉un则表示含糊的)

3、ripple

n.微小的影响,微弱的反响;涟漪

二、Phrase

1、string together

把···连接起来

2、top it (all) off

(以某种方式)结束,完结

三、SpecificNoun

一、问题的提出

二、规范化

1、函数依赖

2、码

3、范式

4、2NF

5、3NF

6、BCNF

7、多值依赖

8、4NF

9、规范化小结

三、数据依赖的公理系统

四、模式的分解

1、模式分解三个定义

2、分解的无损性连接和保持函数依赖性

3、模式分解的算法

五、小结

一、异常概述

二、异常处理机制

1、使用 try...catch捕获异常

2、异常类的继承体系

3、多异常捕获

4、访问异常信息

5、使用finally回收资源

6、异常处理的嵌套

7、Java9增强的自动关闭资源的try语句

三、Checked异常与Runtime异常体系

1、使用throws声明抛出异常

2、方法重写时声明抛出异常的限制

四、使用throw抛出异常

1、抛出异常

2、自定义异常类

3、catch和throw同时使用

4、使用throw语句抛出异常

5、异常链

五、Java的异常跟踪栈

六、异常处理规则

1、不要过度使用异常

2、不要使用过于庞大的try块

3、避免使用 Catch All语句

4、不要忽略捕获到的异常

七、本章小结

异常检测实战过程:
1、基于anomaly_data.csv,可视化数据分布情况,及其对应高斯分布的概率密度函数
2、建立模型,实现异常点数据的预测
3、可视化异常检测处理结果
4、修改概率分布阈值EllipticEnvelope(contamination)中的contamination,查看阈值改变对结果的影响

1、加载数据集

本次实战所用数据集:链接: https://pan.baidu.com/s/18IRYPuk6NSU6xW4NyRokpA 密码: stug

1
2
3
4
5
# load the data
import numpy as np
import pandas as pd
data = pd.read_csv('anomaly_data.csv')
data.head()

2、将数据可视化

1
2
3
4
5
6
7
8
# visualize the data
from matplotlib import pyplot as plt
fig1 = plt.figure(figsize=(10, 5))
plt.scatter(data.loc[:, 'x1'], data.loc[:, 'x2'])
plt.title('data')
plt.xlabel('x1')
plt.ylabel('x1')
plt.show()

图像显示如下:

3、定义x1与x2并展示图像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# define x1 and x2
x1 = data.loc[:, 'x1']
x2 = data.loc[:, 'x2']

fig2 = plt.figure(figsize=(20, 5))

plt.subplot(121)
plt.hist(x1, bins=100)
plt.title('x1 distribut')
plt.xlabel('x1')
plt.ylabel('counts')

plt.subplot(122)
plt.hist(x2, bins=100)
plt.title('x2 distribut')
plt.xlabel('x2')
plt.ylabel('counts')
plt.show()

可视化数据如下所示:

4、计算x1与x2均值和标准差

1
2
3
4
5
6
# calculate the mean and sigma of x1 and x2
x1_mean = x1.mean()
x1_sigma = x1.std()
x2_mean = x2.mean()
x2_sigma = x2.std()
print(x1_mean, x1_sigma, x2_mean, x2_sigma)

5、计算高斯分布的概率密度

1
2
3
4
5
6
7
# calculate the gaussion distribution p(x)
from scipy.stats import norm
x1_range = np.linspace(0, 20, 300)
x1_normal = norm.pdf(x1_range, x1_mean, x1_sigma)

x2_range = np.linspace(0, 20, 300)
x2_normal = norm.pdf(x2_range, x2_mean, x2_sigma)

6、可视化高斯密度曲线

1
2
3
4
5
6
7
8
9
10
11
# visualize the p(x)
fig2 = plt.figure(figsize=(20, 5))
plt.subplot(121)
plt.plot(x1_range, x1_normal)
plt.title('normal p(x1)')

plt.subplot(122)
plt.plot(x2_range, x2_normal)
plt.title('normal p(x2)')

plt.show()

高斯密度曲线可视化如下所示:

7、建立模型并进行预测

1
2
3
4
5
6
7
8
# establish the model and predict
from sklearn.covariance import EllipticEnvelope
ad_model = EllipticEnvelope()
ad_model.fit(data)

# make prediction
y_predict = ad_model.predict(data)
print(pd.value_counts(y_predict))

8、将预测结果可视化

1
2
3
4
5
6
7
8
9
10
# visualize the result
fig4 = plt.figure(figsize=(10, 5))
original_data = plt.scatter(data.loc[:, 'x1'], data.loc[:, 'x2'], marker='x')
anomaly_data = plt.scatter(data.loc[:, 'x1'][y_predict==-1], data.loc[:, 'x2'][y_predict==-1], marker='o', facecolor='none', edgecolor='red', s=150)

plt.title('anomaly detection result')
plt.xlabel('x1')
plt.ylabel('x2')
plt.legend((original_data, anomaly_data), ('original_data', 'anomaly_data'))
plt.show()

异常结果如下所示:

9、修改概率分布阈值,看看影响

1
2
3
ad_model = EllipticEnvelope(contamination=0.02)
ad_model.fit(data)
y_predict = ad_model.predict(data)

将新数据进行可视化:

10、小结

1、通过计算数据各维度对应的高斯分布概率密度函数,可用于寻找数据中的异常点

2、通过修改概率密度阈值contamination,可调整异常点检测的灵敏度

3、核心算法上官网查看https://scikit-learn.org.cn/

结构化查询语言(Structure QUery Language,SQL)是关系数据库的标准语言

一、SQL概述

大多数数据库均采用SQL作为共同的数据存取语言和标准接口

1、SQL的产生与发展

目前没有任何一个数据库能支持SQL标准的所有概念特性,SQL标准的发展如下所示:

2、SQL的特点

它功能极强而又简单易学,集数据查询(data query) 数据操纵(data manipulation) 数据定义(data definition) 数据控制(data control),其特点主要有以下几点:

  • 综合统一

    集很多功能于一体,可以独立完成数据库生命周期中的全部活动

  • 高度非过程化

    只需提出做什么,无需了解存取路径,存取过程以及SQL的操作有系统完成

  • 面向集合的操作方式

    操作对象、查询结果、一次操作(插入、删除、更新)的对象也可以是集合

  • 以同一种语法结构提供多种使用方式

    SQL既是 独立的语言(直接在键盘输入SQL命令进行操作),有时 嵌入式的语言(嵌入到诸如Java、Python的高级语言中)

  • 语法简洁,易学易用

    完成核心动作仅需九个动词,接近英语口语

SQL的动词如下所示:

3、SQL的基本概念

支持数据库的三级模式结构:外模式模式内模式,其中外模式包括: 视图(view) 部分基本表(base table),模式包括 若干基本表,内模式包括 若干存储文件(stored file)。如下图所示:

基本表 视图一样,都是 关系,用户可以用SQL对 基本表视图进行操作。

基本表是本身独立存在表,一个 关系就对应一个 基本表,一个或多个 基本表对应一个存储文件,一个表可以带若干索引,索引也存放在存储文件中。

存储文件的逻辑结构组成了关系数据库的 内模式。存储文件的物理结构对最终用户是隐蔽的

视图是从一个或几个基本表导出的表

二、学生课程数据库的定义

  • Student表
  • Course表
  • SC表

三、数据定义

SQL的数据定义包括 模式定义 表定义 视图定义 索引定义,如下图:

SQL不提供修改模式定义和修改视图定义的操作,修改的话只能删除重建。

一个关系数据库管理系统的实例(instance)中可以建立多个数据库,一个数据库可以建立多个模式,一个模式通常可以包括多个表、视图、索引等数据库对象。

1、模式的定义与删除

(1)定义模式

在SQL中,创建模式的定义语句如下:

CREATE SCHEMA <模式名> AUTHORIZATION <用户名>;

如果没有指定<模式名>,则<模式名>隐含为<用户名>

要创建模式,调用该命令的用户必须具有数据库管理员的权限,或者获得了数据库管理员授予的 CREATE SCHEMA的权限

例题

  • 为用户WANG定义一个学生-课程模式S-T

    1
    CREATE SCHEMA "S-T" AUTHORIZATION WANG;
  • 为用户WANG创建一个模式TEST,并在其中定义一个表TAB1

    1
    2
    3
    4
    5
    6
    7
    8
    CREATE SCHEMA TEST AUTHORIZATION ZHANG
    CREATE TABLE TAB1(
    COL1 SMALLINT,
    COL2 INT,
    COL3 CHAR(20),
    COL4 NUMBERIC(10, 3),
    COL5 DECIMAL(5, 2)
    );
(2)删除模式

删除模式的语句定义如下:

DROP TABLE <模式名> <CASCADE | RESTRICT>

其中 CASCADE RESTRICT两者必选其一,选择了 CASCADE(级联)就表示在删除模式时会级联删除该模式下的所有数据库对象;选择了 RESTRICT(限制)就表示如果模式中已经定义了下属的数据库对象(表、视图等),则拒绝该语句的执行

例题

  • 删除ZHANG并级联删除该模式中的所有数据库对象

    1
    DROP SCHEMA ZHANG CASCADE;

2、基本表的定义、删除与修改

(1)定义基本表

错误描述:当我使用 npm install wangeditor@4.6.3安装这个包是报如下错误,网上的各种诸如重新设置代理都不见效

1
2
3
4
5
6
7
8
9
10
npm ERR! code ECONNRESET
npm ERR! errno ECONNRESET
npm ERR! network request to http://registry.npmjs.org/wangeditor failed, reason: socket hang up
npm ERR! network This is a problem related to network connectivity.
npm ERR! network In most cases you are behind a proxy or have bad network settings.
npm ERR! network
npm ERR! network If you are behind a proxy, please make sure that the
npm ERR! network 'proxy' config is set properly. See: 'npm help config'
npm ERR! A complete log of this run can be found in:
npm ERR! /Users/mr.stark/.npm/_logs/2021-06-18T08_44_30_596Z-debug.log

解决办法

正当我被折磨的死去活来想要放弃时,突然想到我之前用 brew安装软件时遇到过类似的问题,原因是我用了 ClashX这个软件,它启动时会生成一些环境变量,我们复制一下终端代理命令看看

粘贴一下如下所示:

1
export https_proxy=http://127.0.0.1:7890 http_proxy=http://127.0.0.1:7890 all_proxy=socks5://127.0.0.1:7891

接下来我们依次删除这三个环境变量即可

1
2
3
unset https_proxy
unset http_proxy
unset all_proxy

接下来我们就可以开心的使用npm安装其他的包来使用啦!

1
2
3
4
5
+ wangeditor@4.6.3
added 3 packages from 1 contributor, removed 16 packages, updated 1 package and audited 1327 packages in 21.52s

89 packages are looking for funding
run `npm fund` for details

题目描述

n个整数排成的数列,进行如下操作:每次擦去其中两个数a和b,然后在数列中加入一个数 a x b + 1,如此下去直到黑板只剩一个数,在所有按这种操作方式最后得到的数中,最大的记作 max ,最小的为 min,则数列的极差定义为: m = max - min

分析:

以三个数为例:a>b>c,这三个数计算有以下几种结果:

  • ( a x b + 1 ) x c + 1 = a x b x c + c +1
  • ( a x c + 1 ) x b + 1 = a x b x c + b +1
  • ( c x b + 1 ) x a + 1 = a x b x c + a +1

由此可知:先运算小数据得到是大数据,先运算大数据得到的是小数据

我们如是设计代码:用vector存储数据,计算最大数的时候,我们每次娶两个最小的数字计算再将结果 (min1*min2 + 1)放入vector容器中,计算最小数字的时候与之相反即可。

接下来上代码:

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
54
55
56
57
58
59
60
61
62
#include<iostream>
#include<vector>
using namespace std;

//获取数字集中最小的数字并删除
int getTheMin(vector<int> &numbers) {
//遍历
vector <int>::const_iterator i, j = numbers.begin();
int min = *j;
for (i = numbers.begin(); i != numbers.end(); ++i) {
if(*i < *j) {
j = i;
min = *i;
}
}
numbers.erase(j);
return min;
}

//获取数字集中最大的数字并删除
int getTheMax(vector<int> &numbers) {
//遍历
vector <int>::const_iterator i, j = numbers.begin();
int max = *j;
for (i = numbers.begin(); i != numbers.end(); ++i) {
if(*i > *j) {
j = i;
max = *i;
}
}
numbers.erase(j);
return max;
}

int main() {
//存储数据
vector<int> numbers_max;
vector<int> numbers_min;
//元素个数
int n, m;
cin>>n;
//输入
for( int i = 0; i < n; i++ ) {
cin>>m;
numbers_max.push_back(m);
}
numbers_min = numbers_max;
//获取最大值
while(numbers_max.size() != 1) {
int min1 = getTheMin(numbers_max);
int min2 = getTheMin(numbers_max);
numbers_max.push_back(min1*min2 + 1);
}
//获取最小值
while(numbers_min.size() != 1) {
int max1 = getTheMax(numbers_min);
int max2 = getTheMax(numbers_min);
numbers_min.push_back(max1*max2 + 1);
}
cout<<"最大值为:"<<numbers_max.back()<<endl;
cout<<"最小值为:"<<numbers_min.back()<<endl;
}

数据库的数据保护主要包括数据的安全性 完整性,本篇博客只介绍数据库的完整性。

一、数据库安全性概述

数据库的安全性是指保护数据库以防止不合法使用所造成的数据泄露、更改或破坏。

1、数据库的不安全因素

  • a、非授权用户对数据库的恶意存取或破坏
  • b、数据库中重要或敏感数据被泄露
  • c、安全环境的脆弱性

2、安全标准简介

TCSEC/TDI(即紫皮书)从四个方面描述了安全性级别的划分指标,即 安全策略责任 保证以及 文档。每个方面的细节又分为若干项。

根据计算机系统对各项指标的支持情况, TCSEC/TDI将系统划分为4组(division)7个等级,依次为: D、C1、C2、···、A(A1),按照系统的可靠或可信程度逐渐增高,如下表所示:

  • D级

    最低级别,保留该级的目的是为了将一切不符合更高标准的操作系统统归于D组

  • C1级

    能够实现对用户和数据的分离,进行自主存取控制(DAC),保护或限制用户权限的传播

  • C2级

    安全产品的最低档,提供受控的存取保护

  • B1级

    标记安全保护,对系统数据加以标记,并对标记的主体与客体实施强制存取控制(MAC)以及审计等安全机制

  • B2级

    结构化保护,建立形式化的安全策略模型

  • B3级

    安全域,该级的TCB(Trust Computing Base)必须满足访问监控器的要求,审计能力更强,并提供系统恢复过程

  • A1级

    验证设计

二、数据库安全性控制

1、用户身份鉴别

  • 静态口令鉴别
  • 动态口令鉴别
  • 生物特征鉴别
  • 智能卡鉴别

2、存取控制

存取控制主要包括 定义用户权限 合法权限检查两部分

(1)定义用户权限

用户对某一数据对象操作的权利称为权限

(2)合法权限检查

定义用户权限合法权限检查机制 一起组成了数据库管理系统的存取控制子系统

  • C2级数据库管理系统支持 自主存取控制(Discretionary Access Control,DAC)
  • B1级数据库管理系统支持 强制存取控制(Mandatory Access Control,MAC)

这两类方法的简单定义为:

(1)在 自主存取控制方法中,用户对于不同数据库对象有不同的存取权限,不同的用户对同一个对象也有不同的存储权限,而且用户还能将其拥有的权限转授给其他用户

(2)在强制存取控制方法中,每一个数据库对象被标以一定的密级,每一个用户授予某一个级别的许可证,对于任意对象,只有具有合法许可证的用户才能进行强制存取

3、自助存取控制方法

用户权限有两要素组成: 数据库对象 操作类型,定义一个用户的存储权限就是定义该用户可以再那些数据库对象上进行哪些操作。数据自系统中,定义存取权限就称为 授权(authorization)

在关系数据库系统中,存取控制的对象不仅有 数据本身(基本表的数据、属性列上的数据),还有 数据库模式(数据库、基本表、视图、索引的创建),如下图所示:

4、授权:授予与收回

a、GRANT

GRANT用于向用户授予权限,一般格式如下:

GRANT <权限> [, <权限>]······

ON <对象类型> <对象名> [, <对象类型> <对象名>]······

TO <用户> [, <用户>]······

[ WITH GRANT OPTION ];

其语义为:将指定操作对象的指定操作权限授予指定的用户,发出该语句的可以是: 数据库管理员 数据库创建者 已经拥有该权限的用户。接受该权限的可以是一个或者对个用户,也可以是PUBLIC(全体用户)。

若使用了 WITH GRANT OPTION子句,则获得这种权限的用户还可以把这种权限再授予给其他人,若没有使用 WITH GRANT OPTION子句,获得某种权限的用户只能使用该权限而不能传播。

SQL标准不允许循环授权,即被授权者不能将权限再授回给授权者或者其祖先:

例题

  • 把查询Student表的权限授予给用户UI

    1
    2
    3
    GRANT SELECT
    ON TABLE Student
    TO UI;
  • 把对Student表和Course表的全部操作权限赋予给用户U2和U3

    1
    2
    3
    GRANT ALL PRIVILEGES
    ON TABLE Student, Course
    TO U2, U3;
  • 把对SC表的查询权限授予给所有用户

    1
    2
    3
    GRANT SELECT
    ON TABLE SC
    TO PUBLIC;
  • 把查询Student表和修改学生学号的权限授给用户U4(对属性列授权时要明确指明属性列)

    1
    2
    3
    GRANT UPDATE(Sno), SELECT
    ON TABLE Student
    TO U4
  • 将对表SC的插入(INSERT)权限授予给U5,并允许该用户传播该权限

    1
    2
    3
    4
    GRANT INSERT
    ON TABLE SC
    TO U5
    WITH GRANT OPTION
b、REVOKE

授予用户的权限可以由数据库管理员或者其他授权者用REVOKE语句收回,该语句一般格式为:

REVOKE <权限> [, <权限>]······

ON <对象类型> <对象名> [, <对象类型> <对象名>]······

FROM <用户> [, <用户>]······[ CASCADE | RESTRICT ];

废话少说,直接上例题!

例题

  • 将用户U4修改学生学号的权限收回

    1
    2
    3
    REVOKE UPDATE(Sno)
    ON TABLE Student
    FROM U4;
  • 收回所有用户对SC表的查询权限

    1
    2
    3
    REVOKE SELECT
    ON TABLE SC
    FROM PUBLIC;
  • 把用户U5对SC表的INSERT权限收回(将U5权限收回时,会级联收回U5赋予给其他用户的权限,如果其他用户从其他地方获得有对SC表的INSERT的权限则不影响,系统只回收直接或间接从U5获得的权限)

    1
    2
    3
    REVOKE INSERT
    ON TABLE SC
    FROM U5 CASCADE;

    可见,用户可以“自主”地决定将数据的存储权限授予给何人,决定是否也将“授权”的权限授予别人,因此称之为 自主存取控制

c、创建数据库模式的权限

GRANT REVOKE语句用于向用户授予或回收对数据的操作权限,对创建数据库模式一类的数据库对象的授权则由数据库管理员在创建用户时实现

CREATE USER语句格式一般如下:

CREATE USER [ WITH ] [ DBA | RESOURCE | CONNECT ];

  • 只有系统的超级用户才有权限创建一个新的数据库用户
  • 新创建的数据库用户有三种权限: CONNECT RESOURCE DBA
  • GREATE USER如果没有为新建的用户指定权限,则该用户默认拥有 CONNECT 权限
  • 拥有 RESOURCE权限的用户能创建基本表和视图
  • 拥有 DBA权限的用户是系统中心的超级用户,可以创建新的用户、创建模式、创建基本表和视图等;DBA拥有所有对数据库对象的存储权限,还可以将这些权限授予给一般用户

使用下表进行总结:

5、数据库角色

数据库角色是被命名的一组与数据库操作相关的权限,角色是权限的集合

(1)角色的创建

CREATE ROLE <角色名>

刚刚创建的角色是空的,可以使用GRANT为角色授权

(2)给角色授权

GRANT <权限> [, <权限>]······

ON <对象类型> 对象名······

TO <角色> [, <角色>]······

数据库管理员和用户可以利用GRANT语句将权限授予给一个或几个角色

(3)将一个角色授予其他角色或用户

GRANT <角色1> [, <角色2>]······

TO <角色3> [, <用户1>]······

[ WITH ADMIN OPTION ]

将角色授予给某用户或者其他角色,如果指定了 WITH ADMIN OPTION子句,则获得某权限的角色或用户还可以将这种权限授予给其他的角色,一个角色的权限包括: 直接授予给该角色权限 + 其他角色授予给该角色的权限

(4)角色权限的收回

REVOKE <权限> [, <权限>]······

ON <对象类型> <对象名>

FROM <角色> [, <角色>]······

例题

通过角色来将一组权限授予给用户

  • 1、创建一个角色R1

    1
    CREATE ROLE R1;
  • 2、使用GRANT语句,使角色R1拥有Student表的SELECT、UPDATE、INSERT权限

    1
    2
    3
    GRANT SELECT, UPDATE, INSERT
    ON TABLE Student
    TO R1;
  • 3、将这个角色授予给王平、张明、赵玲,使他们具有该角色的权限

    1
    2
    GRANT R1
    TO 王平, 张明, 赵玲;
  • 4、可以一次性的通过R1来收回王平的三个权限

    1
    2
    REVOKE R1
    FROM 王平;
  • 5、角色权限的修改(去掉在Student表删除权限)

    1
    2
    3
    GRANT DELETE
    ON TABLE Student
    TO R1;

由此可以看出,数据库角色是一组权限的集合,可以简化授权的过程

6、强制存取控制方法

如果使用自主存取控制方法,甲将某些数据的存储权限授予给乙,乙就可备份这些数据,并传播这些副本。为了解决此类问题,我们就有了强制存取控制策略:对数据进行敏感性标记。

在这个系统中,数据库管理系统所管理的全部实体被分为主体和客体两大类:

  • 主体:系统中的活动实体,数据库管理系统所管理的实际用户,也包括代表用户的各进程
  • 客体:系统中的被动实体,受主体操控,包括文件、基本表、索引、视图等

对于主体和客体,数据库管理系统为他们每一个实例(值)指派了一个 敏感度标记(label)

敏感度标记被分成若干级别,例如: 绝密(Top Secret, TS) 机密(Secret,S) 可信(Confidential,C) 公开(Public,P)等,密级次序为 TS >= S >= C >= P。主体的敏感度称为 许可证级别(clearance level),客体的敏感度等级称为` 密级(classification level)。

强制存取方法就是通过对比主体和客体的敏感度标记来判断主体是否可以进行存取客体

(1)仅当主体的许可证级别大于或等于客体的密级时,该主体才能读取相应的客体

(2)仅当主体的许可证级别小于或等于客体的密级时,该主体才能写相应的客体强制存取控制是对数据本身进行密级标记