JAVA后端自学技能实操
内容将会持续更新中,有需要添加什么内容可以再评论区留言,大家一起学习
FastDFS
组名:文件上传后所在的 storage 组名称,在文件上传成功后有storage 服务器返回,需要客户端自行保存。
虚拟磁盘路径:storage 配置的虚拟路径,与磁盘选项store_path*对应。如果配置了
store_path0 则是 M00,如果配置了 store_path1 则是 M01,以此类推。
数据两级目录:storage 服务器在每个虚拟磁盘路径下创建的两级目录,用于存储数据文件。
文件名:与文件上传时不同。是由存储服务器根据特定信息生成,文件名包含:源存储
服务器 IP 地址、文件创建时间戳、文件大小、随机数和文件拓展名等信息。
使用docker安装FastDFS(linux)
#拉取镜像
docker pull morunchang/fastdfs
#运行tracker(负载均衡和调度)
docker run -d --name tracker --net=host morunchang/fastdfs sh tracker.sh
#运行storage(作用是文件存储,称之为存储服务器)下面的***.***.***.***为你的公网地址(fastDFS服务器)
docker run -d --name storage --net=host -e TRACKER_IP=***.***.***.***:22122 -e GROUP_NAME=group1 morunchang/fastdfs sh storage.sh
# 进入到storage容器内部
docker exec -it storage /bin/bash
#1 通过命令来查询Nginx的安装位置
root@*******************:/# whereis nginx
#2 查看当前Nginx的进程
root@*******************:/# ps aux | grep nginx
添加以下内容
#3 修改Nginx的配置文件
vi /etc/nginx/conf/nginx.conf
#4 修改Nginx配置内容
server {
listen 80;
server_name localhost;
location ~ /M00 {
# storage 实际存储图片的位置
root /data/fast_data/data;
ngx_fastdfs_module;
}
}
#5 进入到Nginx sbin目录从新加载Nginx配置文件
cd /etc/nginx/sbin
# 重新加载配置文件(切记一定需要重新加载一下配置)
./nginx -s reload
storage存储的位置/data/fast_data/data
#设置开机启动容器
docker update --restart=always tracker
docker update --restart=always storage
集成到springboot项目中
1.加坐标
<!--fastdfs-->
<dependency>
<groupId>com.github.tobato</groupId>
<artifactId>fastdfs-client</artifactId>
</dependency>
2.加配置文件
fast_dfs.properties
#socket连接超时时长
fdfs.soTimeout=1500
#连接tracker服务器超时时长
fdfs.connectTimeout=600
fdfs.trackerList=***.***.***.***:22122
3.书写配置类
@Configuration
@Import(FdfsClientConfig.class) // 导入FastDFS-Client组件
@PropertySource("fast_dfs.properties")
public class FdfsConfiguration {
}
4.书写配置类工具类
@Component
public class FastDFSClient {
@Autowired
private FastFileStorageClient storageClient;
public String uploadFile(MultipartFile file) throws IOException {
StorePath storePath = storageClient.uploadFile((InputStream) file.getInputStream(), file.getSize(), FilenameUtils.getExtension(file.getOriginalFilename()), null);
return storePath.getFullPath();
}
public void delFile(String filePath) {
storageClient.deleteFile(filePath);
}
/**
* 下载
* @param groupName
* @param path
* @return
*/
public byte[] download(String groupName, String path) throws IOException {
InputStream ins = storageClient.downloadFile(groupName, path, new DownloadCallback<InputStream>() {
@Override
public InputStream recv(InputStream ins) throws IOException {
// 将此ins返回给上面的ins
return ins;
}
});
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buff = new byte[100];
int rc = 0;
while ((rc = ins.read(buff, 0, 100)) > 0) {
byteArrayOutputStream.write(buff, 0, rc);
}
return byteArrayOutputStream.toByteArray();
}
}
再需要的项目里面引入fastdfs,写一个配置
@Configuration
@ComponentScan("com.***.***.fastdfs")
public class FastDfsConfiguration {
}
修改application.yml文件,添加自定义的图片访问ip
#图片访问ip
fdfs.url: http://***.***.***.***/
Kafka
安装
- 配置环境
1)查看jdk版本
java -version
查看安装的jdk信息
rpm -qa | grep java
卸载JDK
rpm -e --nodeps jdk版本
切换目录--创建jdk存放目录
cd /usr/local
mkdir jdk
cd jdk
通过Xshell--xftp 6上传jdk压缩包
略
解压压缩包
tar -zxvf jdk-8u201-linux-x64.tar.gz
配置环境jdk变量
vim /etc/profile
输入i进行编辑模式
i
在文件末尾行添加如下
JAVA_HOME=/usr/java/jdk1.8.0_361
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
按键Esc退出编辑模式
保存编辑输入
:wq!
配置生效
source /etc/profile
验证环境变量是否生效
javac
java
2.安装zk
zk是安装kafka集群的必要组件,Kafka通过Zookeeper来实施对元数据信息的管理,包括集
群、主题、分区等内容。
ZooKeeper 官网: http://zookeeper.apache.org/
进入根目录
cd
解压zk
tar zxvf zookeeper-3.4.14.tar.gz
进入安装目录
cd cd zookeeper-3.4.14
进入配置目录
cd conf
改名
mv zoo_sample.cfg zoo.cfg
创建存放数据的目录
cd ..
mkdir data
复制当前data文件路径
cd data
pwd
复制显示的内容
返回上级
cd ..
进入conf目录
cd conf
编辑zoo.cfg文件
vi conf/zoo.cfg
输入i进入编辑模式
i
找到dataDir=/root......这一行
将刚刚复制的路径粘贴到这里的等于后面替换原先的内容
按键Esc退出编辑模式
保存内容
:wq!
进入bin目录
cd ..
cd bin
./zkServer.sh start # 启动
./zkServer.sh status # 查看状态
./zkServer.sh restart # 重启
./zkServer.sh stop # 关闭
查看当前的进程
jps
显示的QuorumPeerMain就是zk
3.安装kafka–单机可远程
下载地址:http://kafka.apache.org/downloads
cd
解压
tar zxvf kafka_2.12-2.2.1.tgz
//创建目录
cd kafka_2.12-2.2.1/
mkdir logs
进入conf 目录
cd conf
vim server.properties
修改config目录下的server.properties文件
再
############################# Socket Server Settings #############################
这一行下面添加host.name=你的公网ip地址
listeners=PLAINTEXT://这里输入你的内网ip:9092
advertised.listeners=PLAINTEXT://这里输入你的公网ip:9092
log.dirs=/root/kafka_2.12-2.2.1/logs 需要在kafka安装目录新建logs目录
zookeeper.connect=你的zk公网ip地址:2181
按键Esc退出编辑模式
保存当前的信息
:wq!
启动kafka
cd ..
bin/kafka-server-start.sh config/server.properties #启动kafka
测试kafka是否生效
重新打开2个窗口进入到kafka的目录里面
cd kafka_2.12-2.2.1
窗口1:
./bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test7----创建主题
./bin/kafka-console-producer.sh --broker-list 你的公网ip地址:9092 --topic test7
窗口2:
./bin/kafka-console-consumer.sh --bootstrap-server 121.43.116.2:9092 --topic test7 --from-beginning
窗口1可以发送消息
窗口2接收消息
kafka/java代码
创建工程kafka-demo
<-- 引入依赖-->
<properties>
<kafka.client.version>2.0.1</kafka.client.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.kafka</groupId>
<artifactId>kafka-clients</artifactId>
<version>${kafka.client.version}</version>
</dependency>
</dependencies>
package com.itheima.kafka.simple;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerConfig;
import org.apache.kafka.clients.producer.ProducerRecord;
import org.apache.kafka.common.protocol.types.Field;
import java.util.Properties;
/**
* 消息生产者
*/
public class ProducerFastStart {
private static final String TOPIC = "test8";
public static void main(String[] args) {
//添加kafka的配置信息
Properties properties = new Properties();
//配置broker信息
properties.put("bootstrap.servers","公网的ip地址:9092");
properties.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringSerializer");
properties.put(ProducerConfig.RETRIES_CONFIG,10);
//生产者对象
KafkaProducer<String,String> producer = new KafkaProducer<String, String>(properties);
//封装消息
ProducerRecord<String,String> record = new ProducerRecord<String, String>(TOPIC,"00001","hello kafka !");
//发送消息
try {
producer.send(record);
}catch (Exception e){
e.printStackTrace();
}
//关系消息通道
producer.close();
}
}
import org.apache.kafka.clients.consumer.ConsumerConfig;
import org.apache.kafka.clients.consumer.ConsumerRecord;
import org.apache.kafka.clients.consumer.ConsumerRecords;
import org.apache.kafka.clients.consumer.KafkaConsumer;
import java.time.Duration;
import java.util.Collections;
import java.util.Properties;
/**
* 消息消费者
*/
public class ConsumerFastStart {
private static final String TOPIC = "test8";
public static void main(String[] args) {
//添加配置信息
Properties properties = new Properties();
properties.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG,"公网ip地址:9092");
properties.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
properties.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG,"org.apache.kafka.common.serialization.StringDeserializer");
//设置分组
properties.put(ConsumerConfig.GROUP_ID_CONFIG,"group2");
//创建消费者
KafkaConsumer<String, String> consumer = new KafkaConsumer<String, String>(properties);
//订阅主题
consumer.subscribe(Collections.singletonList(TOPIC));
while (true){
ConsumerRecords<String, String> records = consumer.poll(Duration.ofMillis(1000));
for (ConsumerRecord<String, String> record : records) {
System.out.println(record.value());
System.out.println(record.key());
}
}
}
}
kafka拓展
-
消息Message
Kafka 中的数据单元被称为消息message,也被称为记录,可以把它看作数据库表中某一行的记录。
-
topic
Kafka将消息分门别类,每一类的消息称之为一个主题(Topic)
-
批次
为了提高效率, 消息会分批次写入 Kafka,批次就代指的是一组消息。
-
分区Partition
主题可以被分为若干个分区(partition),同一个主题中的分区可以不在一个机器上,有可能会部署在多个机器上,由此来实现 kafka 的伸缩性。topic中的数据分割为一个或多个partition。每个topic至少有一个partition。每个partition中的数据使用多个文件进行存储。partition中的数据是有序的,partition之间的数据是没有顺序的。如果topic有多个partition,消费数据时就不能保证数据的顺序。在需要严格保证消息的消费顺序的场景下,需要将partition数目设为1。
-
broker
一个独立的 Kafka 服务器就被称为 broker,broker 接收来自生产者的消息,为消息设置偏移量,并提交消息到磁盘保存。
-
Broker 集群
broker 是集群 的组成部分,broker 集群由一个或多个 broker 组成,每个集群都有一个 broker同时充当了集群控制器的角色(自动从集群的活跃成员中选举出来)。
-
副本Replica
Kafka 中消息的备份又叫做 副本(Replica),副本的数量是可以配置的,Kafka 定义了两类副本:领导者副本(Leader Replica) 和 追随者副本(Follower Replica);所有写请求都通过Leader路由,数据变更会广播给所有Follower,Follower与Leader保持数据同步。如果Leader失效,则从Follower中选举出一个新的Leader。当Follower与Leader挂掉、卡住或者同步太慢,leader会把这个follower从ISR列表(保持同步的副本列表)中删除,重新创建一个Follower。
-
Zookeeper
kafka对与zookeeper是强依赖的,是以zookeeper作为基础的,即使不做集群,也需要zk的支持。Kafka通过Zookeeper管理集群配置,选举leader,以及在Consumer Group发生变化时进行重平衡。
-
消费者群组Consumer Group
生产者与消费者的关系就如同餐厅中的厨师和顾客之间的关系一样,一个厨师对应多个顾客,也就是一个生产者对应多个消费者,消费者群组(Consumer Group)指的就是由一个或多个消费者组成的群体。
-
偏移量Consumer Offset
偏移量(Consumer Offset)是一种元数据,它是一个不断递增的整数值,用来记录消费者发生重平衡时的位置,以便用来恢复数据。
-
重平衡Rebalance
消费者组内某个消费者实例挂掉后,其他消费者实例自动重新分配订阅主题分区的过程。Rebalance 是 Kafka 消费者端实现高可用的重要手段。
kafka集群搭建
mongodb
官网https://www.mongodb.com/zh-cn
MongoDB指的是一个分布式文件存储的数据库(非关系型数据库),支持的数据结构是类似于json和bson格式的
特点是:几乎可以实现类似关系型数据库单表查询的绝大部分的功能,而且是可以支持对数据建立索引
mongodb安装部署
window(mongodb)
下载下来解压之后是这样的
在这个目录下创建data文件夹,在data文件夹中再创建db文件夹和log文件夹,如下图:
再C:\Program Files\MongoDB\Server\4.2文件夹下面灾创建文件mongod.cfg
文件内容如下:
systemLog:
destination: file
path: C:\Program Files\MongoDB\Server\4.2\data\log\mongod.log
storage:
dbPath: C:\Program Files\MongoDB\Server\4.2\data\db
以管理员方式打开cmd,并且进入到这个文件夹下,执行如下命令:
C:\Program Files\MongoDB\Server\4.2\bin\mongod.exe --config C:\Program Files\MongoDB\Server\4.2\mongod.cfg --install
执行完成以后他也没说成功也没说不成功,我们看看日志
在C:\Program Files\MongoDB\Server\4.2\data\log文件夹下产生了一个mongod.log的文件
我们打开看看:
{"t":{"$date":"2023-01-16T11:14:28.335+08:00"},"s":"I", "c":"CONTROL", "id":23303, "ctx":"main","msg":"Service can be started from the command line with 'net start <serviceName>'","attr":{"serviceName":"MongoDB"}}
再C:\Program Files\MongoDB\Server\4.2目录cmd
输入net start MongoDB
看最后一行日志就知道我们安装成功了并且通过命令net start MongoDB就可以启动mongodb的服务了。
这样mongodb就安装好了。
我们来试试玩一下,mongodb默认开的端口是27017,我们来访问一下,
地址:localhost:27017
这就说明mongodb搭建完成了。
连接一下mongodb
我们进入bin目录下点击mongo.exe
创建mall这个数据库,并且进入这个数据库,
use mall
插入数据
db.person.insert({name:"zhangsan",age:"20",gender:"M"})
这里的person相当于mysql中的表,这里不叫表,叫做集合(collections)。集合中的每条记录也不叫记录,叫做文档(document);
查看当前有哪些数据库,
show dbs
或者 show databases
查看当前数据库中有哪些集合
show collections
查询文档:
db.person.find()
db.person.insert({name:"Wangwu",age:"18",gender:"M"})
例如:db.person.find({gender:"M"})
db.person.find({gender:"M"}).count()查看数量或者db.person.find({gender:"M"}).length()
更新db.person.update({name:"zhangsan"},{name:"zhangsan2",age:"20",gender:"M"})
设置属性:db.person.update({name:"zhangsan2"},{$set:{height:175}})
删除属性:
db.person.update({name:"zhangsan2"},{$unset:{height:175}})
删除文档:
db.person.deleteOne({gender:"M"})
删除多条:
db.person.deleteMany({gender:"M"})
可视化navicat工具的15版本是可以连接mongoDB的
linux(mongodb)
通过docker安装MongoDB
#拉取镜像
docker pull mongo:4.0.3
#创建容器
docker create --name mongodb-server -p 27018:27017 -v mongodb-data:/data/db mongo:4.0.3 --auth
#启动容器
docker start mongodb-server
#进入容器
docker exec -it mongodb-server /bin/bash
#进入admin数据库
mongo
use admin
#添加管理员,其拥有管理用户和角色的权限
db.createUser({ user: 'root', pwd: 'root', roles: [ { role: "root", db: "admin" } ] })
#测试,发现是没有权限操作的
> show dbs
2020-10-20T09:09:15.543+0000 E QUERY [js] Error: listDatabases failed:{
"ok" : 0,
"errmsg" : "command listDatabases requires authentication",
"code" : 13,
"codeName" : "Unauthorized"
} :
#进行认证
mongo -u "root" -p "root" --authenticationDatabase "admin"
#通过admin添加普通用户
use admin
db.createUser({ user: 'tanhua', pwd: 'l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV', roles: [ { role: "readWrite", db: "tanhua" } ] });
#通过thor用户登录进行测试
mongo -u "thor" -p "l3SCjl0HvmSkTtiSbN0Swv40spYnHhDV" --authenticationDatabase "admin"
#测试
root@5d848955ff7e:/# mongo -u "thor" -p "thor123" --authenticationDatabase "admin"
MongoDB shell version v4.0.3
connecting to: mongodb://127.0.0.1:27017
Implicit session: session { "id" : UUID("6c368269-30f0-4b29-a224-05a38b5847e2") }
MongoDB server version: 4.0.3
> use thor
switched to db thor
> db.user.insert({id:1,username:'zhangsan',age:20})
WriteResult({ "nInserted" : 1 })
> db.user.find()
{ "_id" : ObjectId("5f8eb2726e0de0aa9517afd3"), "id" : 1, "username" : "zhangsan", "age" : 20 }
可视化界面(mongodb)
数据库操作
mysql | MongoDB | 说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
#查看所有的数据库
show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
#通过use关键字切换数据库
use admin
switched to db admin
#创建数据库
#说明:在MongoDB中,数据库是自动创建的,通过use切换到新数据库中,进行插入数据即可自动创建数据库
use testdb
switched to db testdb
show dbs #并没有创建数据库
admin 0.000GB
config 0.000GB
local 0.000GB
db.user.insert({id:1,name:‘zhangsan’}) #插入数据
WriteResult({ “nInserted” : 1 })
show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
testdb 0.000GB #数据库自动创建
#查看表
show tables
user
show collections
user
#删除集合(表)
db.user.drop()
true #如果成功删除选定集合,则 drop() 方法返回 true,否则返回 false。
#删除数据库
use testdb #先切换到要删除的数据库中
switched to db testdb
db.dropDatabase() #删除数据库
{ “dropped” : “testdb”, “ok” : 1 }
show dbs
admin 0.000GB
config 0.000GB
local 0.000GB
增
#插入数据
#语法:db.COLLECTION_NAME.insert(document)
> db.user.insert({id:1,username:'zhangsan',age:20})
WriteResult({ "nInserted" : 1 })
> db.user.save({id:2,username:'lisi',age:25})
WriteResult({ "nInserted" : 1 })
> db.user.find() #查询数据
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
删
参数说明:
- query :(可选)删除的文档的条件。
- justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
- writeConcern :(可选)抛出异常的级别。
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
> db.user.remove({age:25})
WriteResult({ "nRemoved" : 2 }) #删除了2条数据
#插入4条测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
> db.user.remove({age:22},true)
WriteResult({ "nRemoved" : 1 }) #删除了1条数据
#删除所有数据
> db.user.remove({})
#说明:为了简化操作,官方推荐使用deleteOne()与deleteMany()进行删除数据操作。
db.user.deleteOne({id:1})
db.user.deleteMany({}) #删除所有数据
改
参数说明:
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象和一些更新的操作符(如 , , ,inc…)等,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
db.collection.update(
<query>,
<update>,
[
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
]
)
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 20 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
> db.user.update({id:1},{$set:{age:22}}) #更新数据
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "id" : 1, "username" : "zhangsan", "age" : 22 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
#注意:如果这样写,会删除掉其他的字段
> db.user.update({id:1},{age:25})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25 }
#更新不存在的字段,会新增字段
> db.user.update({id:2},{$set:{sex:1}}) #更新数据
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
#更新不存在的数据,默认不会新增数据
> db.user.update({id:3},{$set:{sex:1}})
WriteResult({ "nMatched" : 0, "nUpserted" : 0, "nModified" : 0 })
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
#如果设置第一个参数为true,就是新增数据
> db.user.update({id:3},{$set:{sex:1}},true)
WriteResult({
"nMatched" : 0,
"nUpserted" : 1,
"nModified" : 0,
"_id" : ObjectId("5c08cb281418d073246bc642")
})
> db.user.find()
{ "_id" : ObjectId("5c08c0024b318926e0c1f6dc"), "age" : 25 }
{ "_id" : ObjectId("5c08c0134b318926e0c1f6dd"), "id" : 2, "username" : "lisi", "age" : 25, "sex" : 1 }
{ "_id" : ObjectId("5c08cb281418d073246bc642"), "id" : 3, "sex" : 1 }
查
- query :可选,使用查询操作符指定查询条件
- fields :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
语法:
db.user.find([query],[fields])
>db.col.find().pretty()
pretty() 方法以格式化的方式来显示所有文档。
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key>:<value> } | db.col.find({"by":"张三"}).pretty() | where by = 张三' |
小于 | {<key>:{$lt:<value>}} | db.col.find({"likes":{$lt:50}}).pretty() | where likes < 50 |
小于或等于 | {<key>:{$lte:<value>}} | db.col.find({"likes":{$lte:50}}).pretty() | where likes <= 50 |
大于 | {<key>:{$gt:<value>}} | db.col.find({"likes":{$gt:50}}).pretty() | where likes > 50 |
大于或等于 | {<key>:{$gte:<value>}} | db.col.find({"likes":{$gte:50}}).pretty() | where likes >= 50 |
不等于 | {<key>:{$ne:<value>}} | db.col.find({"likes":{$ne:50}}).pretty() | where likes != 50 |
#插入测试数据
db.user.insert({id:1,username:'zhangsan',age:20})
db.user.insert({id:2,username:'lisi',age:21})
db.user.insert({id:3,username:'wangwu',age:22})
db.user.insert({id:4,username:'zhaoliu',age:22})
db.user.find() #查询全部数据
db.user.find({},{id:1,username:1}) #只查询id与username字段
db.user.find().count() #查询数据条数
db.user.find({id:1}) #查询id为1的数据
db.user.find({age:{$lte:21}}) #查询小于等于21的数据
db.user.find({age:{$lte:21}, id:{$gte:2}}) #and查询,age小于等于21并且id大于等于2
db.user.find({$or:[{id:1},{id:2}]}) #查询id=1 or id=2
#分页查询:Skip()跳过几条,limit()查询条数
db.user.find().limit(2).skip(1) #跳过1条数据,查询2条数据
db.user.find().sort({id:-1}) #按照age倒序排序,-1为倒序,1为正序
索引/UI工具(mongodb)
#查看索引
> db.user.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "testdb.user"
}
]
#说明:1表示升序创建索引,-1表示降序创建索引。
#创建索引
> db.user.createIndex({'age':1})
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"numIndexesAfter" : 2,
"ok" : 1
}
#删除索引
db.user.dropIndex("age_1")
#或者,删除除了_id之外的索引
db.user.dropIndexes()
#创建联合索引
db.user.createIndex({'age':1, 'id':-1})
#查看索引大小,单位:字节
db.user.totalIndexSize()
MongoDB 查询分析可以确保我们建议的索引是否有效,是查询语句性能分析的重要工具。
#插入1000条数据
for(var i=1;i<1000;i++)db.user.insert({id:100+i,username:'name_'+i,age:10+i})
#查看执行计划
> db.user.find({age:{$gt:100},id:{$lt:200}}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "testdb.user",
"indexFilterSet" : false,
"parsedQuery" : {
"$and" : [
{
"id" : {
"$lt" : 200
}
},
{
"age" : {
"$gt" : 100
}
}
]
},
"winningPlan" : { #最佳执行计划
"stage" : "FETCH", #查询方式,常见的有COLLSCAN/全表扫描、IXSCAN/索引扫描、FETCH/根据索引去检索文档、SHARD_MERGE/合并分片结果、IDHACK/针对_id进行查询
"inputStage" : {
"stage" : "IXSCAN",
"keyPattern" : {
"age" : 1,
"id" : -1
},
"indexName" : "age_1_id_-1",
"isMultiKey" : false,
"multiKeyPaths" : {
"age" : [ ],
"id" : [ ]
},
"isUnique" : false,
"isSparse" : false,
"isPartial" : false,
"indexVersion" : 2,
"direction" : "forward",
"indexBounds" : {
"age" : [
"(100.0, inf.0]"
],
"id" : [
"(200.0, -inf.0]"
]
}
}
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "c493d5ff750a",
"port" : 27017,
"version" : "4.0.3",
"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
},
"ok" : 1
}
====================================================================
#测试没有使用索引
> db.user.find({username:'zhangsan'}).explain()
{
"queryPlanner" : {
"plannerVersion" : 1,
"namespace" : "testdb.user",
"indexFilterSet" : false,
"parsedQuery" : {
"username" : {
"$eq" : "zhangsan"
}
},
"winningPlan" : {
"stage" : "COLLSCAN", #全表扫描
"filter" : {
"username" : {
"$eq" : "zhangsan"
}
},
"direction" : "forward"
},
"rejectedPlans" : [ ]
},
"serverInfo" : {
"host" : "c493d5ff750a",
"port" : 27017,
"version" : "4.0.3",
"gitVersion" : "7ea530946fa7880364d88c8d8b6026bbc9ffa48c"
},
"ok" : 1
}
springboot整合mongodb
https://spring.io/projects/spring-data-mongodb
- 导入依赖
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.0.RELEASE</version>
</parent>
<groupId>cn.itcast.mongodb</groupId>
<artifactId>itcast-mongodb</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- java编译插件 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
</project>
- 编写application.properties配置文件
# Spring boot application
spring.application.name = thor-mongodb
#无认证信息的配置
#spring.data.mongodb.uri=mongodb://localhost:27017/thor
#springboot 配置
spring.data.mongodb.username=thor
spring.data.mongodb.password=*******************
spring.data.mongodb.authentication-database=admin
spring.data.mongodb.database=thor
spring.data.mongodb.port=27018
spring.data.mongodb.host=localhost
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//启动类
@SpringBootApplication
public class MongoApplication {
public static void main(String[] args) {
SpringApplication.run(MongoApplication.class, args);
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.bson.types.ObjectId;
//实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Thor {
private ObjectId id;
private String name;
private int age;
private Address address;
}
===============================================================
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
//实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Address {
private String street;
private String city;
private String zip;
}
//mapper层
import cn.itcast.mongodb.pojo.Thor;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import java.util.List;
@Component
public class ThorDao {
@Autowired
private MongoTemplate mongoTemplate;
public void saveThor(Thor thor ) {
this.mongoTemplate.save(thor);
}
public List<Thor> queryThorListByName(String name) {
Query query = Query.query(Criteria.where("name").is(name));
return this.mongoTemplate.find(query, Thor.class);
}
public List<Thor> queryThorPageList(Integer page, Integer rows) {
Query query = new Query().limit(rows).skip((page - 1) * rows);
return this.mongoTemplate.find(query, Thor.class);
}
public UpdateResult update(Thor thor) {
Query query = Query.query(Criteria.where("id").is(thor.getId()));
Update update = Update.update("age", thor.getAge());
return this.mongoTemplate.updateFirst(query, update, Thor.class);
}
public DeleteResult deleteById(String id) {
Query query = Query.query(Criteria.where("id").is(id));
return this.mongoTemplate.remove(query, Thor.class);
}
}
//测试单元
import cn.test.mongodb.dao.ThorDao;
import cn.test.mongodb.pojo.Address;
import cn.test.mongodb.pojo.Thor;
import org.bson.types.ObjectId;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestThorDao {
@Autowired
private ThorDao thorDao;
@Test
public void testSave() {
Thor thor = new Thor(ObjectId.get(), "张三", 20,
new Address("人民路", "上海市", "666666"));
this.thorDao.saveThor(thor);
}
@Test
public void testQuery() {
List<Thor> thorList = this.thorDao.queryPersonListByName("张三");
for (Thor thor : thorList) {
System.out.println(thor);
}
}
@Test
public void testQuery2() {
List<Thor> thorList = this.thorDao.queryThorPageList(2, 2);
for (Thor thor : thorList) {
System.out.println(thor);
}
}
@Test
public void testUpdate() {
Thor thor = new Thor();
thor.setId(new ObjectId("5c0956ce235e192520086736"));
thor.setAge(30);
this.thorDao.update(thor);
}
@Test
public void testDelete() {
this.thorDao.deleteById("5c09ca05235e192d8887a389");
}
}
批量删除和修改
首先需要导入相关的依赖包,如mongo-java-driver等。
创建与数据库连接的客户端对象(MongoClient)并指定服务器地址和端口号。
获取到目标集合(Collection)的引用。
构造查询条件,根据自己的业务需求设置不同的查询条件。
调用deleteMany()方法进行批量删除操作,传入查询条件参数。示例代码如下所示:
import com.mongodb.*;
public class MongoDBExample {
public static void main(String[] args) throws Exception {
// 创建与数据库连接的客户端对象
MongoClient mongoClient = new MongoClient("localhost", 27017);
// 获取到目标集合的引用
DB database = mongoClient.getDB("thor_database");
DBCollection collection = database.getCollection("thor_collection");
// 构造查询条件
BasicDBObject query = new BasicDBObject();
query.put("age", new BasicDBObject("$gte", 18));
// 执行批量删除操作
WriteResult result = collection.remove(query).multi(true);
System.out.println("Deleted " + result.getN() + " documents.");
// 关闭数据库连接
mongoClient.close();
}
}
总结(mongodb)
docker
安装
yum 包更新到最新
yum update
安装需要的软件包, yum-util 提供yum-config-manager功能,另外两个是devicemapper驱动依赖的
yum install -y yum-utils device-mapper-persistent-data lvm2
设置yum源
yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装docker,出现输入的界面都按 y
yum install -y docker-ce
查看docker版本,验证是否验证成功
docker -v
登录阿里云配置镜像加速器
https://cr.console.aliyun.com/cn-hangzhou/instances/mirrors
复制下面的命令即可
ElasticSearch
安装
linux
使用docker安装ElasticSearch
拉取镜像
docker pull elasticsearch:7.4.0
创建容器
docker run -id --name elasticsearch --restart=always -d -p 9200:9200 -p 9300:9300 -v /usr/share/elasticsearch/plugins:/usr/share/elasticsearch/plugins -e “discovery.type=single-node” elasticsearch:7.4.0
输入网址:公网地址:9200显示如下
配置Ik分词器
因为在创建elasticsearch容器的时候,映射了目录,所以可以在宿主机上进行配置ik中文分词器
在去选择ik分词器的时候,需要与elasticsearch的版本好对应上
#切换目录
cd /usr/share/elasticsearch/plugins
#新建目录
mkdir analysis-ik
cd analysis-ik
#root根目录中拷贝文件
mv elasticsearch-analysis-ik-7.4.0.zip /usr/share/elasticsearch/plugins/analysis-ik
#解压文件
cd /usr/share/elasticsearch/plugins/analysis-ik
unzip elasticsearch-analysis-ik-7.4.0.zip
查看当前的docker进程
docker ps
重启当前的docker---这里的CONTAINER ID需要选择的是对应的ES的docker--这一步必须操作否则后面使用分词器会报错"analyzer [ik_smart] not found for field [title]"
docker restart CONTAINER ID
查看启动的日志---这里的CONTAINER ID需要选择的是对应的ES的docker
docker logs -f CONTAINER ID
设置开机启动
docker update --restart=always elasticsearch
dooker安装kibana环境
拉取镜像
docker pull kibana:7.4.0
docker run -d -p 5601:5601 --link elasticsearch -e "ELASTICSEARCH_URL=http://***.***.***.**:9200" kibana:7.4.0
通信
Socket
Netty框架
Netty是一个异步(指的是调用的时候不是值异步的IO)的基于时间驱动的网络应用框架,用于快速开发可维护,高性能的网络服务器和客户端,实现跨域请求
基于NIO的开发