dream

一个菜鸟程序员的成长历程

0%

term query

term是表达语义的最小单位 ,搜索和利用统计语言模型进行自然语言处理都需要处理 term

特点

  • term level query: term query/range query/ exists query / prefix query / wildcard query
  • 在ES里面,term 查询不做分词,把term查询作为一个整体词汇进行查询,进行一个精确匹配,并对匹配结果进行算分
  • 可以通过 Constant Score 将查询转换成一个 filtering ,避免算分,并利用缓存,提高性能

term 查询

我们现在有数据如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
"_index" : "test",
"_type" : "_doc",
"_id" : "ID10032_1194_1634175220_535254",
"_score" : 6.151313,
"_source" : {
"user_id" : 10032,
"consultant_company_id" : 1194,
"type" : 9,
"source" : 1,
"operation_at" : 1634175220,
"create_time" : "2021-10-14 09:33:40",
"update_time" : "2021-10-14 09:33:40",
"login_type" : 3,
"true_name" : "张三",
"id" : "ID10032_1194_1634175220_535254"
}
}

如果我们使用match查询

这里ID10032_1194_1634175220_535254大写id10032_1194_1634175220_535254小写都可以

1
2
3
4
5
6
7
8
GET test_user_action_detail/_search
{
"query": {
"match": {
"id": "ID10032_1194_1634175220_535254"
}
}
}

都可以得到搜索结果

如果使用 term 查询,id10032_1194_1634175220_535254可以查询到数据,但是如果是ID10032_1194_1634175220_535254大写,那么term 查询就查询不到数据了

1
2
3
4
5
6
7
8
9
10
GET test_user_action_detail/_search
{
"query": {
"term": {
"id": {
"value": "id10032_1194_1634175220_535254"
}
}
}
}

原因在于 该 id 字段的 mapping 是 text/keyword

1
2
3
4
5
6
7
8
9
"id" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}

text数据类型会进行分词,也就是大写会被分词成小写。所以text的id数据实际会变成小写id10032_1194_1634175220_535254,而term查询区分大小写,会进行精确匹配,如果只有搜索小写才能搜索出来结果。如果不想进行分词,那么可以使用keyword字段类型搜索,把term查询语句改成下面这样

1
2
3
4
5
6
7
8
9
10
GET test_user_action_detail/_search
{
"query": {
"term": {
"id.keyword": { //这里使用keyword字段查询
"value": "ID10032_1194_1634175220_535254"
}
}
}
}

这样就可以得到结果了,因为keyword不进行分词,所以插入的ID10032_1194_1634175220_535254就还是ID10032_1194_1634175220_535254,不过注意,这样的话小写id10032_1194_1634175220_535254就搜索不到结果了

filter 不进行算分

对于term查询来说,其实没必要算分,因为是精确搜索,那么就可以使用filter查询来避免算分并可以有效利用缓存,可以提升性能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
GET test_user_action_detail/_search
{
"query": {
"constant_score": {
"filter": {
"term": {
"id.keyword": {
"value": "ID10032_1194_1634175220_535254"
}
}
}
}
}
}

基于全文查询

  • match query / match phrase query / query string query

  • 特点

    • 索引和搜索都会进行分词,查询字符串先传递到一个合适的分词器,然后生成一个供查询的词项列表
    • 查询时,会先分词,然后对每个词都进行查询,最终将结果进行合并。并为每个文档生成一个算分。
    • 例如查询matrx reloaded 会查询到 matrxreloaded两个词的搜索结果,然后进行合并。

range query

range 可以进行范围查询

1
2
3
4
5
range: {
created_at: {
gt:'1889237773'
}
}

exists query

可以判断值是否存在

1
2
3
exists:{
field:"created_at"
}

处理多值字段

比如有一个数组 [北京市,上海市]

如果我们使用term查询

1
2
3
4
5
6
7
8
9
10
11
GET test_user_action_detail/_search
{
"query": {
"term": {
"city.keyword": {
"value": "北京市"
}
}
}
}

就会搜索出现上面的数据,因为对于数组来说,term 查询是只要包含那么就会搜索出来。

极客时间 ES 学习笔记

nginx

nginx的场景

三个主要场景

  • 静态资源:通过本地文件系统提供服务
  • 反向代理:nginx的强大性能,缓存,负载均衡
  • API服务:openresty

nginx的优点

  • 高并发,高性能
  • 可扩展性好
  • 高可靠性
  • 热部署
  • BSD许可证

nginx的组成

  • nginx二进制可执行文件:由各模块原码编译出的一个文件
  • nginx.conf:控制nginx行为
  • access.log
  • error.log

vim nginx语法高亮

如果想要vim操作nginx的时候有语法高亮,那么只需要把nginx文件夹带的vim配置文件复制到自己的vim配置文件下面就可以了

找到nginx源码目录,注意这里是源码目录,下载的tar包解压出来的目录,而不是编译安装后的目录,下面有一个contrib文件夹,这个文件夹里面有vim文件夹,把这个里面的配置文件都复制一下就好了

1
cp -r nginx/contrib/vim/ ~/.vim/

已安装的nginx 增加模块

首先到达源码目录cd /usr/local/src/nginx1.19

然后开始编译

  • –prefix 参数代表你的nginx安装目录,如果是已安装的nginx,那么这个目录就选择已安装的目录,没有安装的可以随便选想安装到的目录
  • –with 开头的代表你想开启的模块
1
sudo ./configure --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_realip_module --prefix=/usr/local/src/nginx

然后执行make

1
sudo make

接下来就可以复制nginx源文件了,这里只执行make,不需要执行make install

现在假设你已经在nginx源码目录了

1
2
cd ./objs  //移动到objs目录下
cp nginx /usr/local/src/nginx/sbin/ //把objs目录下的nginx复制到你原来的nginx安装目录下面的sbin目录替换原来的nginx源文件

如果是新安装,那么不需要复制,直接执行 sudo make install 就可以了

配置语法

  • 配置文件由指令和指令块构成
  • 每条指令以;分号结尾,指令与参数间用空格分隔
  • 指令块以{}大括号将多条指令组织在一起
  • include 语句允许组合多个配置文件以提升可维护性
  • 使用 #井号添加注释,提高可读性
  • 使用 $符号作为变量
  • 部分指令的参数支持正则表达式

http配置的指令块

  • http
  • server
  • upstream
  • location

nginx 命令行

  • 帮助 -h
  • 指定配置文件 -c
  • 指定配置指令 -g
  • 指定运行目录 -p
  • 发送信号 -s
  • 测试配置文件语法 -t
  • 打印版本信息 -v -V
1
2
3
4
5
nginx             //启动
nginx -s reload // 重启
nginx -s quit //优雅停止
nginx -s stop //直接停止
nginx -s reopen //重新开始记录日志

热部署

当你需要升级nginx或者增加模块的时候可以使用热部署的方式平滑过渡,不需要重启

查看现在nginx进程的id

1
ps -ef|grep nginx

对现在的nginx进程发送USR2信号进行热部署

1
kill -USR2 id

现在可以看到新的nginx进程和老的nginx进程都存在了,这个时候我们需要让老的nginx进程平滑退出

1
kill -WINCH id

接下来就可以看到老的nginx的worker进程全部平滑退出了,但是老的master进程还在,这是为了防止新的有问题,还可以退回老的

如果接下来新的有问题,那么我们退回老的,发送HUP信号,而不是直接reload

1
kill -HUP id

接下来可以看到老的worker进程都起来了

如果热部署后没有问题的话,那么我们直接删除老的master进程就可以了

1
kill -QUIT id

日志切割

如果我们觉得日志太大可以进行日志切割,一种是发送reopen信号,还有一种是发送USR1信号

1
sudo nginx -s reopen

或者

1
kill -USR1 id

但是注意切割之前要把之前的日志备份一下,不然就会被删除啦

反向代理

反向代理配置在http代码块中

首先通过upstream配置反向代理的服务器

test 是一个名称,可以随便取

1
2
3
upstream test{
server 127.0.0.1:8080 # 上游服务器的地址,可以写多个
}

通过 proxy_pass 进行反向代理

1
2
3
4
5
6
server{
listen 80;
location / {
proxy_pass http://test; # 这里填写上面的upstream名字
}
}

这个时候我们访问80端口实际上访问的是8080端口

反向代理的缓存

反向代理之后还可以在反向代理服务器做缓存

nginx.conf文件的http代码块中设置缓存

1
2
# 设置缓存路径 /tmp/nginxCache 缓存名称 my_cache
proxy_cache_path /tmp/nginxCache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

接下来在我们的反向代理server/location代码块里面使用这个缓存

1
2
3
4
5
6
location / {
proxy_cache my_cache; # 使用上面定义的缓存
proxy_cache_key $host$uri$is_args$args; # 缓存的key值,根据host uri和参数来做key
proxy_cache_valid 200 304 302 1d; # 缓存200 304 302状态 缓存时间1d = 1天
proxy_pass http://test; # 这里填写上面的upstream名字
}

goaccess 日志可视化

goaccess 是一个c语言写的日志可视化工具

直接编译安装

1
2
3
4
5
6
wget http://tar.goaccess.io/goaccess-1.2.tar.gz
tar -xzvf goaccess-1.2.tar.gz
cd goaccess-1.2/
./configure --enable-utf8
make
make install

然后就可以启动了,直接启动就可以

指定日志文件路径 /usr/local/src/nginx/logs/access.log -o 输出到某个html文件中 –real-time-html 代表实时刷新, –log-format 代表日志格式 ,–daemonize 代表守护进程后台执行 仅在 开启了 –real-time-html 实时刷新有效

1
goaccess /usr/local/src/nginx/logs/access.log -o ~/wwwroot/goaccess.html --real-time-html --log-format=COMBINED --daemonize

这里要注意,如果开启了 –real-time-html 实时刷新,那么会启动一个 socket 进程监听 7890 端口,所以 7890 端口要开放才行

可以配置 nginx 文件访问这个输出的 html 文件了,就可以看到一个可视化界面了

ssl

ssl(Secure Sosckets Layer)
tls(Transport Layer Security)

  • 1995年-ssl3.0
  • 1999 - tls1.0
  • 2006 - tls1.1
  • 2008 - tls1.2
  • 2018 - tls1.3

ssl/tls 运行在 ISO7层模型的表示层中,而http协议运行在表示层的上层应用层。在http的数据传输到表示层以后,ssl/tls就会对数据进行加密

  • 握手
  • 交换秘钥
  • 告警
  • 对称加密的应用数据

tls安全套件

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  • tls代表tls加密
  • ECDHE 代表秘钥交换算法
  • RSA 代表身份验证算法
  • AES 代表对称加密算法
  • 128 代表强度
  • GCM 代表分组模式
  • SHA256 代表签名 hash 算法

nginx

nginx的场景

三个主要场景

  • 静态资源:通过本地文件系统提供服务
  • 反向代理:nginx的强大性能,缓存,负载均衡
  • API服务:openresty

nginx的优点

  • 高并发,高性能
  • 可扩展性好
  • 高可靠性
  • 热部署
  • BSD许可证

nginx的组成

  • nginx二进制可执行文件:由各模块原码编译出的一个文件
  • nginx.conf:控制nginx行为
  • access.log
  • error.log

vim nginx语法高亮

如果想要vim操作nginx的时候有语法高亮,那么只需要把nginx文件夹带的vim配置文件复制到自己的vim配置文件下面就可以了

找到nginx源码目录,注意这里是源码目录,下载的tar包解压出来的目录,而不是编译安装后的目录,下面有一个contrib文件夹,这个文件夹里面有vim文件夹,把这个里面的配置文件都复制一下就好了

1
cp -r nginx/contrib/vim/ ~/.vim/

已安装的nginx 增加模块

首先到达源码目录cd /usr/local/src/nginx1.19

然后开始编译

  • –prefix 参数代表你的nginx安装目录,如果是已安装的nginx,那么这个目录就选择已安装的目录,没有安装的可以随便选想安装到的目录
  • –with 开头的代表你想开启的模块
1
sudo ./configure --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_realip_module --prefix=/usr/local/src/nginx

然后执行make

1
sudo make

接下来就可以复制nginx源文件了,这里只执行make,不需要执行make install

现在假设你已经在nginx源码目录了

1
2
cd ./objs  //移动到objs目录下
cp nginx /usr/local/src/nginx/sbin/ //把objs目录下的nginx复制到你原来的nginx安装目录下面的sbin目录替换原来的nginx源文件

如果是新安装,那么不需要复制,直接执行 sudo make install 就可以了

配置语法

  • 配置文件由指令和指令块构成
  • 每条指令以;分号结尾,指令与参数间用空格分隔
  • 指令块以{}大括号将多条指令组织在一起
  • include 语句允许组合多个配置文件以提升可维护性
  • 使用 #井号添加注释,提高可读性
  • 使用 $符号作为变量
  • 部分指令的参数支持正则表达式

http配置的指令块

  • http
  • server
  • upstream
  • location

nginx 命令行

  • 帮助 -h
  • 指定配置文件 -c
  • 指定配置指令 -g
  • 指定运行目录 -p
  • 发送信号 -s
  • 测试配置文件语法 -t
  • 打印版本信息 -v -V
1
2
3
4
5
nginx             //启动
nginx -s reload // 重启
nginx -s quit //优雅停止
nginx -s stop //直接停止
nginx -s reopen //重新开始记录日志

热部署

当你需要升级nginx或者增加模块的时候可以使用热部署的方式平滑过渡,不需要重启

查看现在nginx进程的id

1
ps -ef|grep nginx

对现在的nginx进程发送USR2信号进行热部署

1
kill -USR2 id

现在可以看到新的nginx进程和老的nginx进程都存在了,这个时候我们需要让老的nginx进程平滑退出

1
kill -WINCH id

接下来就可以看到老的nginx的worker进程全部平滑退出了,但是老的master进程还在,这是为了防止新的有问题,还可以退回老的

如果接下来新的有问题,那么我们退回老的,发送HUP信号,而不是直接reload

1
kill -HUP id

接下来可以看到老的worker进程都起来了

如果热部署后没有问题的话,那么我们直接删除老的master进程就可以了

1
kill -QUIT id

日志切割

如果我们觉得日志太大可以进行日志切割,一种是发送reopen信号,还有一种是发送USR1信号

1
sudo nginx -s reopen

或者

1
kill -USR1 id

但是注意切割之前要把之前的日志备份一下,不然就会被删除啦

反向代理

反向代理配置在http代码块中

首先通过upstream配置反向代理的服务器

test 是一个名称,可以随便取

1
2
3
upstream test{
server 127.0.0.1:8080 # 上游服务器的地址,可以写多个
}

通过 proxy_pass 进行反向代理

1
2
3
4
5
6
server{
listen 80;
location / {
proxy_pass http://test; # 这里填写上面的upstream名字
}
}

这个时候我们访问80端口实际上访问的是8080端口

反向代理的缓存

反向代理之后还可以在反向代理服务器做缓存

nginx.conf文件的http代码块中设置缓存

1
2
# 设置缓存路径 /tmp/nginxCache 缓存名称 my_cache
proxy_cache_path /tmp/nginxCache levels=1:2 keys_zone=my_cache:10m max_size=10g inactive=60m use_temp_path=off;

接下来在我们的反向代理server/location代码块里面使用这个缓存

1
2
3
4
5
6
location / {
proxy_cache my_cache; # 使用上面定义的缓存
proxy_cache_key $host$uri$is_args$args; # 缓存的key值,根据host uri和参数来做key
proxy_cache_valid 200 304 302 1d; # 缓存200 304 302状态 缓存时间1d = 1天
proxy_pass http://test; # 这里填写上面的upstream名字
}

goaccess 日志可视化

goaccess 是一个c语言写的日志可视化工具

直接编译安装

1
2
3
4
5
6
wget http://tar.goaccess.io/goaccess-1.2.tar.gz
tar -xzvf goaccess-1.2.tar.gz
cd goaccess-1.2/
./configure --enable-utf8
make
make install

然后就可以启动了,直接启动就可以

指定日志文件路径 /usr/local/src/nginx/logs/access.log -o 输出到某个html文件中 –real-time-html 代表实时刷新, –log-format 代表日志格式 ,–daemonize 代表守护进程后台执行 仅在 开启了 –real-time-html 实时刷新有效

1
goaccess /usr/local/src/nginx/logs/access.log -o ~/wwwroot/goaccess.html --real-time-html --log-format=COMBINED --daemonize

这里要注意,如果开启了 –real-time-html 实时刷新,那么会启动一个 socket 进程监听 7890 端口,所以 7890 端口要开放才行

可以配置 nginx 文件访问这个输出的 html 文件了,就可以看到一个可视化界面了

ssl

ssl(Secure Sosckets Layer)
tls(Transport Layer Security)

  • 1995年-ssl3.0
  • 1999 - tls1.0
  • 2006 - tls1.1
  • 2008 - tls1.2
  • 2018 - tls1.3

ssl/tls 运行在 ISO7层模型的表示层中,而http协议运行在表示层的上层应用层。在http的数据传输到表示层以后,ssl/tls就会对数据进行加密

  • 握手
  • 交换秘钥
  • 告警
  • 对称加密的应用数据

tls安全套件

TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256

  • tls代表tls加密
  • ECDHE 代表秘钥交换算法
  • RSA 代表身份验证算法
  • AES 代表对称加密算法
  • 128 代表强度
  • GCM 代表分组模式
  • SHA256 代表签名 hash 算法

学堂在线C++程序设计第十四章学习笔记

异常处理

1
2
3
4
5
try{
throw //抛出异常
} catch (异常) {
//异常处理
}

异常接口声明

  • 一个函数显式声明可能抛出的异常,有利于函数的调用者为异常处理做好准备
  • void fun() throw(A,B,C)
  • 若无异常接口声明,则可以抛出任何类型的异常
  • 不抛任何类型异常的函数声明如下:
    void fun() throw()

异常处理的构造与析构

自动的析构

  • 找到一个匹配的catch异常处理后
  • 初始化异常参数
  • 将从对应的try块开始到异常被抛出之间构造(且尚未析构)的所有自动对象进行析构
  • 从最后一个catch处理之后开始恢复执行

标准程序库异常处理

基础

  • exception
  • logic_error 表示可以被预先检测到的异常
    • 这类异常可以避免
  • runtime_error 表示难以被预先检测到的异常

学堂在线C++程序设计第十三章学习笔记

流类库与输入输出

IO流的概念

当程序与外界环境进行信息交换时,存在着两个对象,一个是程序中的对象,另一个是文件对象

是信息流动的抽象,负责在数据的生产者消费者之间建立联系,并管理数据的流动

流对象与文件操作

  • 建立流对象
  • 指定这个流对象与某个文件对象建立连接
  • 程序操作流对象
  • 流对象通过文件系统对所连接的文件对象产生作用

提取与插入

  • 读操作从流中提取
  • 写操作向流中写入

输出流

最重要的三个输出流

  • ostream
  • ofstream
  • ostringstream

预先定义的输出流对象

  • cout 标准输出
  • cerr 标准错误输出,没有缓冲,发送给它的内容立即被输出
  • clog 类似cerr,但是有缓冲,缓冲区满时被输出
1
2
3
4
ofstream fout('123.log');
streamBuf* old = cout.rdbuf(fout.rdbuf());
//cout 输出到123.log文件
cout.rdbuf(old); //恢复输出到标准输出

构造输出流对象

  • ofstream 类支持磁盘文件输出
  • 如果在构造函数中指定文件名,当构造这个文件时该文件时自动打开的
    ofstream fout(‘123.log’);
  • 可以在调用默认构造函数后使用open打开文件
    ofstream fout;
    fout.open(123.log);
  • 打开文件可以指定模式
    ofstream fout(‘123.log’, ios_base::out|ios_base::binary);

文件输出流成员函数的三种类型

  • 与操纵符等价的成员函数
  • 执行非格式化写操作的成员函数
  • 其他修改流状态且不同于操纵符或插入运算符的成员函数

成员函数

  • open
    • 把流与磁盘文件关联
    • 需要指定打开模式
  • put
    • 把一个字符写到输出流
  • write
    • 将内存中的一块内容写到一个文件输出,可以写二进制
  • seekp和 tellp
    • 操作文件流的内部指针
  • close
    • 关闭磁盘文件
  • 错误处理函数
    • 在写到一个流时进行错误处理

向文本文件输出

插入运算符 <<

  • 为所有标准C++数据类型设计的,用于传送一个字节到输出流对象

操纵符(manipulator)

  • 插入运算符和操纵符一起
    控制输出格式
  • 很多操纵符都定义在 ios_base类中,如hex(),头文件中,如setprecision()
  • 控制输出宽度
    在流中放入setw操纵符或调用width成员函数
  • setw和 width只影响紧随其后的输出项,但其他流格式操纵符保持有效直到发生改变
  • dec,oct和 hex操纵符设置输入输出的默认进制

精度

  • 浮点数输出精度的默认值是6
  • 改变精度使用 setprecision操纵符,定义在 头文件中
  • 如果不指定 fixed 或 scientifc,精度值表示有效数字位数
  • 如果设置了 ios_base::fixed 定点形式 或 ios_base::scientifc 科学计数法 ,精度值表示小数点之后的位数

向二进制文件输出

二进制文件流

  • 使用ofstream构造函数中的模式指定二进制
  • 以通常方式构造一个流,然后使用setmode成员函数,在文件打开后改变模式
  • 通过二进制文件输出流对象完成输出
1
2
3
4
5
6
7
int main() {
int b[3] ={912,2456,37890};
ofstream file("date.bat", ios_base::binary);
file.write(reinterpret_cast<char *> (&b), sizeof(b));
file.close();
return 0;
}

向字符串输出

  • 用于构造字符串
  • 功能
    • 支持ofstream类的除了open,close外的所有操作
    • str函数可以返回当前已构造的字符串
  • 典型应用
    • 将数值转换为字符串
1
2
3
ostringstream os;
os << 123;
string s = os.str();

输入流

重要的输入流类

  • istream 最适用于顺序文本输入,cin是他的实例
  • ifstream 支持磁盘文件输入
  • istringstream 字符串输入

构造输入流对象

  • 如果在构造函数中指定文件,在构造对象时自动打开
    ifstream ifs(‘data.bat’);
  • 调用默认构造函数后使用open打开
    ifstream ifs;
    ifs.open(‘data.bat’);
  • 打开文件时可以指定模式

输入流相关函数

  • open 把输入流和文件关联
  • get 函数的功能与提取运算符(>>)很像,主要的不同点是get函数在读入数据时包括空白字符
  • getLine 的功能是读取多个字符,并且可以指定终止字符,读取完成后,从读取内容中删除终止字符
  • read 函数从一个文件读字节到内存中的指定区域,由长度确定要读的字节数。当遇到文件结束或在文本模式文件中遇到文件结束标记字符时结束读取。可以读取二进制。
1
2
3
4
5
6
7
8
9
10
11
12
13
int main() {
int b[3] ={912,2456,37890};
ofstream file("date", ios_base::binary);
file.write(reinterpret_cast<char *> (b), sizeof(b));
file.close();
int i2;
ifstream mfile("date", ios_base::binary);
mfile.seekg(2 * sizeof(int));
mfile.read(reinterpret_cast<char *>(&i2), sizeof(int));
cout << i2 <<endl;
mfile.close();
return 0;
}

字符串输入

用于从字符串读取数据

输入输出流

输入输出流都是从iostream派生的

  • fstream
  • stringstream

数据库系统原理第十三节

数据库安全和保护

安全性与访问控制

数据库安全:指保护数据库以防止不合法的使用而造成数据泄露,更改或破坏,所以安全性对于任何一个DBMS来说都是至关重要的

  • 身份验证
  • 数据库用户权限确认

查看用户

1
select user from mysql.user

创建用户

1
create user user[identified by [password]'password']

create user ‘test‘@’%’ identified by ‘123’

create user ‘tset‘@’%’ identified by password ‘jdkfjalkdjskflajsdfa’

删除用户

1
drop user user

drop user ‘test‘@’%’

修改用户

1
rename user old_user to new_user

修改密码

1
set password for 'test'@'%' = PASSWORD('pass')

账号权限管理

使用grant 为用户授权

1
2
3
4
5
grant
priv_type[column]
on [object_type] priv_level
to user
[with grant option]

grant select (id, name)
on test.test_table
to test@’localhost’

收回用户权限

1
2
3
4
revoke 
priv_type
on [object_type]
from user

revoke select on test.test_table from ‘test‘@’localhost’

事务与并发控制

所谓事务是用户定义的一个数据操作序列,这些操作可作为一个完整的工作单元,要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务中的操作一般是对数据的更新操作,包括增删改

begin transaction开始
commit 或 rollback结束

事务的特征

  • A 原子性
  • C 一致性
  • I 隔离性
  • D 持续性
并发操作问题
  • 丢失更新
  • 不可重复读
  • 读‘脏’数据
封锁

封锁 是最常用的并发控制技术

基本思想:需要时,事务通过向系统请求对它所希望的数据对象加锁,以确保它不被非预期改变

数据库系统原理第十四节

数据库安全和保护

事务与并发控制

所谓事务是用户定义的一个数据操作序列,这些操作可作为一个完整的工作单元,要么全部执行,要么全部不执行,是一个不可分割的工作单位。事务中的操作一般是对数据的更新操作,包括增删改

begin transaction开始
commit 或 rollback结束

事务的特征

  • A 原子性
  • C 一致性
  • I 隔离性
  • D 持续性
并发操作问题
  • 丢失更新
  • 不可重复读
  • 读‘脏’数据
封锁

封锁 是最常用的并发控制技术

基本思想:需要时,事务通过向系统请求对它所希望的数据对象加锁,以确保它不被非预期改变

一个实质上就是允许或阻止一个事务对一个数据对象的存取特权

基本的封锁类型

  • 排它锁,用于写操作
  • 共享锁,用于读操作

封锁的粒度
粒度越细,并发性就越大,但软件复杂性和系统开销也就越大

封锁的级别又称为一致性级别或隔离度

  • 0级封锁:不重写其他非0级封锁事务的未提交的更新数据
  • 1级封锁:不允许重写未提交的更新数据。防止了丢失更新的发生
  • 2级封锁:既不重写也不读未提交的更新数据(防止了读脏数据)
  • 3级封锁:不读未提交的更新数据,不写任何(包括读操作)未提交数据

活锁:先来先服务
死锁:预防

  • 一次性锁请求
  • 锁请求排序
  • 序列化处理
  • 资源剥夺

可串行性
一组事务的一个调度就是它们的基本操作的一种排序

在数据库系统中,可串行性就是并发执行的正确性准则

两段封锁法

  • 发展或加锁阶段
  • 收缩或释放锁阶段

备份与恢复

备份

1
2
3
4
5
select * into outfile 'file_name' export_options  
dumpfile 'file_name'
fields terminated by ',' 逗号分隔
optionally enclosed by "" 字符串用双引号
lines terminated by '?' 问号分隔每行数据

dumpfile 导出的备份文件里面所有的数据都彼此紧挨着

导入

1
2
3
4
load data infile 'file_name' into table table_name
fields terminated by ',' 逗号分隔
optionally enclosed by "" 字符串用双引号
lines terminated by '?' 问号分隔每行数据

数据库生命周期

  • 需求分析
  • 系统功能与数据库的设计
  • 系统功能与数据库的实现
  • 测试与维护

php mysql应用

连接数据库非持久连接

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<?php
$con = mysql_connect("localhost:3306","root","123456");

持久连接 mysql_pconnect

选择数据库 mysql_select_db("test", $con)

执行 sql mysql_query("set names 'gbk'")

$res = mysql_query($sql, $con);

$array = mysql_fetch_array($res, MYSQL_NUM);

mysql_close($con) or die("关闭失败");

学堂在线C++程序设计第十二章学习笔记

泛型程序设计和标准模板库

泛型及STL

泛型程序设计

  • 编写不依赖于具体数据类型的程序
  • 将算法从特定的数据结构中抽象出来成为通用的
  • C++的模板为泛型程序设计奠定了关键的基础

术语:概念

  • 可以比较大小的数据类型记作Comparable
  • 具有公有的复制函数并可以用 = 赋值的记作Assignable
  • 将 可以比较大小 并且 具有公有复制函数可以用 = 赋值的记作Sortable

对于两个不同的概念A,B,如果A所需求的所有功能也是B所需求的,那么B是A的子概念,比如,Sortable是 Comparable 的子概念,也是 Assignable的子概念

术语:模型

  • 符合一个概念的数据类型称为该概念的模型
  • 比如 int 型是 Comparable的模型
  • 静态数组不是 Assignable的模型

STL

  • 标准模板库STL定义了一套概念体系,为泛型程序设计提供了逻辑基础
  • STL中的各个类模板,函数模板的参数都是用这个体系中的概念来规定的
  • 使用STL模板时,类型参数既可以是C++标准库中已有的类型,也可以是自定义的类型–只要这些类型是所要求的概念的模型

STL基本组件

  • 容器(container):容纳,包含一组元素的对象
    • 顺序容器:
      array,vector,双端队列,单链表,列表
    • 有序容器:
      集合,多重集合,map,多重映射
    • 无序关联容器
      无序集合,无序多重集合,无序映射,无序多重映射
  • 迭代器(iterator)
    • 提供了顺序访问容器中每个元素的方法
    • 可以使用 ++ 运算符来获得指向下一个元素的迭代器
    • 可以使用 * 运算符访问迭代器指向的元素,如果元素类型是类或结构体,还可以使用 -> 运算符直接访问成员
    • 有些迭代器还支持通过 – 运算符获得指向上一个元素的迭代器
    • 迭代器是泛化的指针:指针也具有同样的特性,因此指针本身就是一种迭代器
    • 使用独立于STL容器的迭代器,需要包含头文件
  • 函数对象(function object)
  • 算法(algorithms)

迭代器算法容器的桥梁

  • 将迭代器作为算法的参数,通过迭代器来访问容器而不是把容器直接作为算法参数
  • 函数对象作为算法参数而不是将函数所执行的运算作为算法的一部分。
  • 使用STL中提供的或自定义的迭代器和函数对象,配合STL的算法,可以组合出各种各样的功能

容器适配器

  • 队列

迭代器

迭代器是算法和容器的桥梁

  • 迭代器用作访问容器中的元素
  • 算法不直接操作容器中的数据,而是通过迭代器间接操作

算法和容器独立

  • 增加新的算法,无需影响容器的实现
  • 增加新的容器,原有的算法也可以适用

输入流迭代器

  • istream_iterator
  • 以输入流 如 cin 为参数构造
  • 可用 *(p++) 获得下一个输入的元素

输出流迭代器

  • ostream_iterator
  • 构造时需要提供输出流 如 cout
  • 可用 (*p++) = x 将 x 输出到输出流

二者都属于适配器

  • 适配器是用来为已有对象提供新的接口的对象
  • 输入流适配器和输出流适配器为流对象提供了迭代器的接口

容器的基本功能和分类

  • 容器类是容纳,包含一组元素或元素集合的对象
  • 基于容器中元素的组织方式分类:顺序容器,关联容器
  • 按照与容器所关联的迭代器类型分类:可逆容器,随机访问容器

顺序容器

顺序容器的基本功能
  • STL中的顺序容器
    • 向量
    • 双端队列(deque)
    • 列表(list)
    • 单向链表(forward_list)
    • 数组(array)
  • 元素线性排列,可以随时在指定位置插入元素和删除元素
  • 必须符合 Assignable 这一概念(具有共有的复制构造函数并可以用 ‘=’ 赋值)
  • array 对象的大小固定,forward_list有特殊的添加和删除操作

顺序容器的接口(不包含单向链表和数组)

  • 构造函数
  • 赋值函数:assign
  • 插入函数: insert, push_front(只对list和deque),push_back, emplace, emplace_front
  • 删除函数:erase, clear, pop_front, pop_back, emplace_back
  • 首尾元素的直接访问:front, back
  • 改变大小:resize

顺序容器的特征

向量

  • 特点
    • 一个可以扩展的动态数组
    • 随机访问,在尾部插入或删除元素块
    • 在中间或头部插入或删除元素慢
  • 容量
    • 容量:实际分配空间的大小
    • s.capacity: 返回当前容量
    • s.reserve(n): 容量小于n,则对s进行扩展,使其容量至少为n

双端队列

  • 特点
    • 在两端插入或删除元素快
    • 在中间插入或删除元素慢
    • 随机访问较快,但比向量慢

列表

  • 特点
    • 在任意位置插入和删除元素都很快
    • 不支持随机访问
  • 接合操作(splice)
    • s.splice(p, s2, q1, q2): 将s2中[q1,q2)移动到s1中p所指向元素之前

顺序容器的插入迭代器与适配器

顺序容器的插入迭代器

  • 用于向容器头部,尾部或中间指定位置插入元素的迭代器
  • 包括前插迭代器(front_inserter),后插迭代器(back_inserter)和任意位置插入迭代器(inserter)
  • 例子:
    list s;
    back_iserter iter(s);
    *(iter++) = 5; //通过iter把5插入s末尾

顺序容器的适配器

  • 以顺序容器为基础构建一些常用数据结构,是对顺序容器的封装
    • 队列
    • 优先级队列:最 的先弹出

栈和队列模板

  • 栈模板
    template <class T, class Sequence = deque> class stack;
  • 队列模板
    template <class T,class FrontInsertionSequence = deque> class queue;
  • 栈可以用任何一种顺序容器作为基础容器,而队列只允许用前插顺序容器(双端队列或列表)

栈和队列共同支持的操作

  • 比较
  • 返回元素个数
  • empty
  • push
  • pop
  • 不支持迭代器,因为不允许对任意元素访问

栈和队列不同的操作

  • 栈的操作
    s.top 返回栈顶元素的引用
  • 队列操作
    s.front 获得队头元素的引用
    s.back 获得队尾元素的引用

优先级队列

  • 优先级队列也像栈和队列一样支持元素的压入和弹出,但元素弹出顺序和元素大小有关,每次弹出最大的
  • template <class T, class Sequence = Vector> class priority_queue
  • 优先级队列的基础容器必须是支持随机访问的顺序容器
  • 支持栈和队列的size,empty, push, pop几个函数
  • 优先级队列并不支持比较操作
  • 与栈类似,优先级队列提供一个 top 函数,可以获得下一个即将被弹出元素的引用

关联容器

分类和基本功能

关联容器的特点

  • 每个关联容器都有一个key
  • 可以根据key高效查找元素

接口

  • 插入insert
  • 删除 erase
  • 查找 find
  • 定界 lower_bound,upper_bound,equal_bound
  • 计数 count

集合

集合用来存储一组无重复的数据。用于集合的元素本身是有序的,可以高效查找元素,也可以方便的得到指定大小范围的元素在容器中所处的区间

映射

映射和集合的主要区别

  • 集合的元素类型是key本身

  • 映射的元素类型是key,value二元组

  • 在集合中按照key查找一个元素时,一般只是确定这个元素是否存在。

  • 映射中按照key查找时,除了能确定是否存在外,还可以得到相应的附加数据

多重集合和多重映射

  • 多重集合允许有重复元素的集合,多重映射允许一个key对应多个value
  • 多重集合与集合,多重映射与映射的用法差不多

函数对象

函数对象

  • 一个行为类似函数的对象
  • 可以没有参数,也可以带有若干参数
  • 其功能是获取值,或者改变操作状态
  • 普通函数就是函数对象
  • 重载了 “()” 运算符的类的实例是函数对象

函数适配器

  • 绑定适配器
    • bind1st, bind2nd: 将n元函数对象的指定参数绑定为一个常数,得到n-1元函数对象
  • 组合适配器
    • not1,not2: 将指定谓词的结果取反
  • 函数指针适配器
    • ptr_fun: 将一般函数指针转换为函数对象,使之能够作为其他函数适配器的输入
    • 在进行参数绑定或其他转换的时候,通常需要函数对象的类型信息
  • 成员函数适配器:ptr_fun,ptr_fun_ref
    • 对成员函数指针使用,把n元成员函数适配为n + 1元函数对象,该函数对象的第一个参数为调用该成员函数时的目的对象
    • 也就是 object->method() 变成 method(object)
    • 将 object->method(arg1) 变成 method(object, arg1)

STL算法

本身是一种函数模板

  • 通过迭代器获得输入数据
  • 通过函数对象对数据进行处理
  • 通过迭代器将结果输出

STL算法是通用的,独立于具体的数据类型,容器类型

分类

  • 不可变序列算法
    • 不直接修改所操作的容器内容的算法
    • 用于查找指定元素,比较是否相等,对元素进行计数等
  • 可变序列算法
    • 可修改所操作的容器对象的算法
    • 包括复制,删除,替换,洗牌及生成一个序列的算法
  • 排序和搜索算法
    • 对序列排序
    • 搜索
    • 堆算法
  • 数值算法
    • 求和,求差,积等

数据库系统原理第十一节

数据库编程

存储过程体

使用 declare 声明局部变量

1
declare cid int(10) 0;
  • 只能值begin end中声明
  • 必须在存储过程开头声明
  • 不同于用户变量
  • 作用范围仅限于声明他的begin end语句块

局部变量和用户变量的区别

  • 局部变量前面没有@符号,并且他只能被声明的begin end语句块中使用
  • 用户变量在声明时前面有@符号,同时已声明的用户变量存在于整个会话之中

使用 set 为局部变量赋值

1
set cid = 910;

select id into cid table

流程控制语句

条件判断
if 条件 then
表达式1
else
表达式2
end if

循环语句

  • while
  • repeat
  • loop

iterate语句
用于表示退出当前循环

declare cursor创建游标

1
declare cursor_name cursor for select_statement

open 打开游标

1
open cursor_name

使用 fetch into 读取游标数据
读取已打开的游标

1
fetch cursor_name into var_name

使用 close 关闭游标

1
close cursor_name

存储函数

由SQL语句和过程式语句组成

使用 create function 创建

1
2
3
create function sp_name(参数)
returns type
routine_body //主体

给定id号返回性别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
use test;
delimiter $$
create function fn_search(cid int)
returns char(20)
deterministic
begin
declare sex char(20)
select cust_sex into sex from customers where id = cid;
if sex is null then
return(select '没有该客户');
else
if sex = 'F' then
return(select '女');
else
return(select '男');
end if;
end if;
end $$

存储函数和存储过程的区别
存储函数不能有输出参数,存储过程有
存储函数必须包含一条return语句,存储过程不包含return
存储函数可以直接调用,不需要call,存储过程必须call

使用 select 调用存储函数

1
select fn_search(1)$$

删除存储函数

1
drop function fun_name

数据库安全和保护

数据库完整性

正确性和相容性

  • 列级约束,包含列的类型,取值范围,精度
  • 元组约束,指元组中各个字段之间的约束
  • 表级约束,指若干元组,关系之间的联系的约束

实体完整性:主键约束和候选键约束

主键

  • 一个表只能有一个主键
  • 主键唯一,不能为NULL
  • 复合主键不能包含不必要的多余列
  • 一个列名在复合主键的列表中只能出现一次

主键约束:primary key, create table 或 alter table,一个表只能创建一个主键
候选键约束:unique, create table 或 alter table,可以定义若干个候选键

参照完整性
1
2
3
4
5
references table_name(index_col_name)
[on delete reference_option]
[on update reference_option]

restrict|cascade|set null|no action

数据库系统原理第十二节

数据库安全和保护

数据库完整性

1
2
3
4
5
6
7
8
create table orders
order_id int not null auto_increment,
cust_id int not null default 0,
primary key(order_id),
foreign key(cust_id)
refrences table_name(id)
on delete restrict
on update restrict

用户定义完整性约束

非空 约束 not null
check 约束 check(sex = ‘f’)

命名完整性约束 constraint[指定的约束名字]
只能给基于表的完整性约束指定名字
基于列的不行

更新完整性约束
使用alter table更新与列或表有关的各种约束

  • 完整性约束不能直接修改(先删除,再增加)
  • alter table 独立删除完整性约束,而不会删除表,drop table删除表也会删除完整性约束

触发器

用户定义在关系表上的一类由事件驱动的数据对象,也是一种保证数据完整性的方法

创建触发器

1
2
create trigger 名称 时间 事件
onfor each row 主体

插入数据时改变变量值

1
2
create trigger t_name after insert
on table_name for each row set @str = 'one customer added';

使用触发器

insert 触发器

  • 可引用一个名为 new 的虚拟表,来访问被插入的行
  • before insert , new 中的值可以被更新
    delete 触发器
  • 可引用 old的虚拟表,来访问被删除的行
  • old 只读
    update 触发器
  • 可引用old的虚拟表来访问update执行前的值,也可以引用new访问更新后的值

安全性与访问控制

数据库安全:指保护数据库以防止不合法的使用而造成数据泄露,更改或破坏,所以安全性对于任何一个DBMS来说都是至关重要的

  • 身份验证
  • 数据库用户权限确认

查看用户

1
select user from mysql.user