MongoDB

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

现如今MongoDB因设计极简、灵活,数据模型面向文档(这里的文档是一种类似于JSON的结构,称为BSON,是JSON的增强版)已成为快速开发互联网Web应用程序首选的数据库。

1、MongoDB下载与安装

1.1、使用Docker下载与安装

关于MongoDB的下载与安装,我们主要以学习相关知识为主,一定是怎么简单怎么来。所以我们采用Docker一键安装与部署。

# 1.拉取mongo镜像文件
docker pull mongo:5.0.6# 2.运行容器
docker run -d -p 27017:27017 \
-v /home/mongo/config:/data/configdb \
-v /home/mongo/db:/data/db \
--name mongo \
mongo:5.0.6# 进入容器输入 mongo 进入 MongoDB shell
[root@laizhenghua mongo]# docker exec -it mongo /bin/bash
root@ac473b08d011:/# mongo# 3.创建 mongo 数据库管理员用户
# 3.1.切换admin库
use admin
# 3.2.创建root用户,作为管理员用户
db.createUser({user: "root", pwd: "lijiana", roles: ["root"]})# 3.3.登录root用户
db.auth("root", "lijiana")# 3.4.创建一个 test 库
use test

检测是否安装成功,出现如下字样表示安装成功

1.2、MongoDB的配置文件

MongoDB也支持通过配置文件自定义一些东西,例如监听的端口号,数据文件存放路径和日志文件等。在Linux系统中配置文件一般命名为mongodb.conf

mongodb.conf

# 数据库文件存储位置
dbpath = /data/db
# log文件
logpath = /data/logs/mongodb.log
# 使用追加的方式写日志
logappend = true
# 端口
port = 27017
# 是否以守护进程方式运行
# fork = true
# 是否启用认证
auth = true
# 设置oplog的大小(MB)
oplogSize = 2048

重新启动容器

[root@laizhenghua mongo]# docker rm -f mongo
# 在/home/mongo/config目录下新建 mongodb.conf
[root@laizhenghua config]# vim mongodb.conf
# 将上面内容复制进去即可
[root@laizhenghua config]# cat mongodb.conf
# 数据库文件存储位置
dbpath = /data/db
# log文件
logpath = /data/logs/mongodb.log
# 使用追加的方式写日志
logappend = true
# 端口
port = 27017
# 是否以守护进程方式运行
# fork = true
# 是否启用认证
auth = true
# 设置oplog的大小(MB)
oplogSize = 2048# 给日志文件及目录授权,注意这一步非常重要!!!
[root@laizhenghua /]# chmod 777 /home/mongo/logs/mongodb.log# 重新启动容器 通过 -f 命令指定配置文件运行
docker run -d -p 27017:27017 \
-v /home/mongo/config:/data/configdb \
-v /home/mongo/db:/data/db \
-v /home/mongo/logs:/data/logs \
--name mongo \
mongo:5.0.6 \
-f /data/configdb/mongodb.conf

需要注意的是一定要给宿主日志文件所在的路径及文件授权,否则会抛出caused by :: Failed to open /data/logs/mongodb.log的错误。

# 授权
chmod 777 /home/mongo/logs/mongodb.log
# 目录挂载
/home/mongo/logs:/data/logs

2、MongoDB的基本操作

2.1、基本概念与客户端工具连接

文档 / documnet:类似于JS中的对象,在MongoDB中每一条数据都是一个文档。

集合 / collection:集合就是一组文档,也就是集合是用来存放文档的。集合中存储的文档可以是各种各样的,没有格式要求。

因此在MongoDB中多个文档组成集合,多个集合组成数据库。并且数据库和集合都不需要手动创建,当我们创建文档时,如果文档所在的集合或数据库不存在会自动创建数据库和集合。

基础命令:

# 显示数据库
> show databases
> show dbs# 例如
> db.auth("root", "lijiana")
1
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB# 进入 test 数据库 没有则创建
use test
# 查看当前所在数据库
> db
test
# 显示数据库中所有的集合
> show collections

为了操作方便,不用每次都进入MongoDB shell,MongoDB也可以使用客户端工具进行连接与访问,例如使用Navicat Premium 15连接:

# 使用客户端连接之前先给数据库创建一个用于登录的用户
> use test
switched to db test
> db.createUser({user: "root", pwd: "lijiana", roles: ["readWrite", "dbAdmin"]})
Successfully added user: { "user" : "root", "roles" : [ "readWrite", "dbAdmin" ] }


例如:

2.2、数据库的CRUD操作

官方文档地址:https://www.mongodb.com/docs/manual/crud/

1、添加

// 向数据库中插入一个或多个文档 语法:db.collection.insert(document, options)
// 栗子:向 test 数据库中的 userList 集合中插入一个用户对象use test;
db.userList.insert({name: "alex", pwd: "123", age: 18});// 插入多个文档 如果文档没有指定 _id 属性 则数据库自动为文档添加 _id 该属性作为文档的唯一标识/主键
use test;
db.userList.insert([{name: "java", pwd: "123", age: 20},{name: "python", pwd: "123", age: 50},{name: "php", pwd: "123", age: 10}
]);
// 扩展
db.collection.insertOne(document, options); // 插入一个文档
db.collection.insertMany(document, options); // 插入多个文档

2、查询

// 查询当前集合中的文档 语法:db.collection.find(query) 可以接收一个对象作为条件参数
// 注意:find()返回的是一个数组 言外之意可以使用下标或索引取到一个文档// 栗子1:查询userList集合中的所有文档
db.userList.find();
// db.userList.find({}); 效果是一样的// 栗子2(单个条件):在userList集合查询name=java的文档
db.userList.find({"name": "java"});// 栗子3(多个条件):在userList集合查询name=python并且age=50的文档
db.userList.find({"name": "python", age: 50});// 扩展
db.collection.findOne(); // 用来查询集合中符合条件的第一个文档 返回一个文档
db.userList.findOne({"name": "python", age: 50}).name; // python// 查询结果数量
db.userList.find({}).length();
db.userList.find({}).count();// 如果是内嵌文档 在MongoDB中也支持内嵌文档作为查询条件(使用.的形式来匹配) 例如
use test;
db.userList.update({"name": "alex"}, [{$set: {hobby: {movies: "hero",code: "Java",mobile: "Iphone 13"},update_time: "$$NOW"}
}]);
// 栗子4(内嵌文档作为查询条件):查询爱好有喜欢java的文档
// 如果通过内嵌文档来对文档进行查询 此时属性名必须使用引号(双引号/单引号都行)
db.userList.find({"hobby.code": "Java"});


查询结果集投影,这里的投影是指对结果集筛选字段,控制字段的返回与否

// 我们使用关系型数据查询数据时,通常都是需要那个字段就查询那个字段,在MongoDB中也可以
use test;
db.userList.find({}, {name: 1}); // 只查询_id和name字段 _id字段默认都返回db.userList.find({}, {_id: 0, name: 1, age: 1}); // 只查询name和age两个字段

3、修改

// 修改文档数据 语法:db.collection.update(query, [{$set: {update}}]) query是查询条件 {update}是新对象/文档/*
$set关键字解释:1.在MongoDB中$开头的关键字称为修饰器或操作符,后面还有$inc/$push/$pull/$pop2.如果文档只更新一部分,通常使用修饰器修改,这种操作是原子性的更新速度与效率极快3.实际上是一种特殊的键,用来指定复杂的更新操作,比如调整、增加或者删除、还可以操作数组或者内嵌的文档,非常方便4.$set用来重新指定一个属性或字段的值,如果这个属性或字段不存在则创建
*/// 栗子:修改name=alex的文档,年龄为30
db.userList.update({"name": "alex"}, [{$set: {age: 30, update_time: "$$NOW"}}]); // NOW为系统变量 当前时间
db.userList.find({"name": "alex"}).pretty();// $unset 删除指定的属性// 扩展
db.collection.updateOne(query, [{$set: {update}}]); // 修改一个符合条件的文档
db.collection.updateMany(query, [{$set: {update}}]); // 同时修改多个符合条件的文档 update() 默认情况下只会改一个// 例如 update() 第三个参数还可以传配置项 可以多看看官方文档
db.collection.update(<query>,<update>,{upsert: <boolean>,multi: <boolean>,writeConcern: <document>,collation: <document>,arrayFilters: [ <filterdocument1>, ... ],hint:  <document|string>, // Added in MongoDB 4.2let: <document> // Added in MongoDB 5.0}
)


4、删除

// 关于删除记住两个API即可
// db.collection.deleteOne(filter, options);
// db.coolection.deleteMany(filter, options);// db.inventory.deleteMany({}); 删除所有文档/清空集合// 扩展
db.collection.drop(); // 删除集合
db.dropDatabase(); // 删除数据库// 栗子:删除name=php的文档
use test;
db.userList.deleteOne({"name": "php"});
db.userList.find();

实际上以上API就是最常用的几个,学习时先记住这几个完全够用了。在开发中如果遇到不会的或是特殊的需求查一查相关文档即可。

2.3、操作符Operators

MongoDB中操作符Operators有查询和投影操作符(Query and Projection Operators)、更新操作符(Update Operators)、聚合管道操作符(Aggregation Pipeline Operators)等功能强大,操作非常方便。一切为简化操作数据而生,详见官方文档。

官方文档地址:https://www.mongodb.com/docs/manual/reference/operator

1、比较查询操作符

/*
$eq    匹配等于指定值的值
$gt    匹配大于指定值的值
$gte   匹配大于或等于指定值的值
$in    匹配数组中指定的任何值
$lt    匹配小于指定值的值
$lte   匹配小于或等于指定值的值
$ne    匹配所有不等于指定值的值
$nin   不匹配数组中指定的任何值
*/
// $lt 查询年龄小于30的文档
db.userList.find({age: {$lt: 30}});// $gt $lt 查询年龄在10~50之间的文档
db.userList.find({age: {$gt: 10, $lt: 50}});

2、逻辑查询操作符

/*
$and    使用逻辑连接查询子句AND会返回与两个子句的条件匹配的所有文档
$not    反转查询表达式的效果并返回与查询表达式不匹配的文档
$nor    使用逻辑连接查询子句NOR会返回所有未能匹配两个子句的文档
$or     使用逻辑连接查询子句OR返回与任一子句的条件匹配的所有文档
*/
// $or 查询年龄等于10或20的文档
db.userList.find({$or: [{age: 10}, {age: 20}]});

3、元素查询操作符

/*
$exists  匹配具有指定字段的文档
$type    如果字段属于指定类型,则选择文档
*/

4、评估查询操作符

/*
$expr     允许在查询语言中使用聚合表达式
$jsonSchema    根据给定的 JSON Schema 验证文档
$mod      对字段的值执行模运算并选择具有指定结果的文档
$regex    选择值与指定正则表达式匹配的文档
$text     执行文本搜索
$where    匹配满足 JavaScript 表达式的文档
*/

5、数组查询操作符

/*
$all    匹配包含查询中指定的所有元素的数组
$elemMatch    如果数组字段中的元素与所有指定$elemMatch条件匹配,则选择文档
$size   如果数组字段为指定大小,则选择文档
*/

6、字段更新操作符

/*
$currentDate    将字段的值设置为当前日期,可以是日期或时间戳
$inc    将字段的值增加指定的数量
$min    仅当指定值小于现有字段值时才更新字段
$max    仅当指定值大于现有字段值时才更新字段
$mul    将字段的值乘以指定的数量
$rename    重命名字段
$set    设置文档中字段的值
$setOnInsert    如果更新导致插入文档,则设置字段的值对修改现有文档的更新操作没有影响
$unset    从文档中删除指定的字段
*/

7、数组更新操作符

/*
$    充当占位符以更新与查询条件匹配的第一个元素
$[]    充当占位符,为匹配查询条件的文档更新数组中的所有元素
$[<identifier>]    充当占位符,arrayFilters为符合查询条件的文档更新符合条件的所有元素
$addToSet    仅当集合中尚不存在元素时,才将元素添加到数组中
$pop    删除数组的第一项或最后一项
$pull    删除与指定查询匹配的所有数组元素
$push    将项目添加到数组
$pullAll    从数组中删除所有匹配的值
*/

8、算术表达式操作符

/*
$abs    返回数字的绝对值
$add    添加数字以返回总和,或添加数字和日期以返回新日期,如果添加数字和日期,则将数字视为毫秒,接受任意数量的参数表达式,但最多一个表达式可以解析为日期
$ceil    返回大于或等于指定数字的最小整数
$divide    返回第一个数字除以第二个数字的结果,接受两个参数表达式
$exp    将e 提高到指定的指数
$floor    返回小于或等于指定数字的最大整数
$ln    计算数字的自然对数
$log    计算指定基数中数字的对数
$log10    计算一个数字的以 10 为底的对数
$mod    返回第一个数字除以第二个数字的余数,接受两个参数表达式
$multiply    乘以数字以返回产品,接受任意数量的参数表达式
$pow    将数字提高到指定的指数
$round    将数字四舍五入为整数或指定的小数位
$sqrt    计算平方根
$trunc    将数字截断为整数或指定的小数位
*/

补充$subtract返回第一个值减去第二个值的结果,如果这两个值是数字,则返回差值,如果这两个值是日期,则返回以毫秒为单位的差异,如果这两个值是日期和以毫秒为单位的数字,则返回结果日期接受两个参数表达式如果这两个值是日期和数字,请先指定日期参数,因为从数字中减去日期没有意义

9、数组表达式操作符

/*
$arrayElemAt    返回指定数组索引处的元素
$arrayToObject    将键值对数组转换为文档
$concatArrays    连接数组以返回连接的数组
$filter    选择数组的一个子集以返回一个仅包含与过滤条件匹配的元素的数组
$first    返回第一个数组元素区别于$first蓄能器
$in    返回一个布尔值,指示指定的值是否在数组中
$indexOfArray    在数组中搜索指定值的出现并返回第一次出现的数组索引,如果未找到子字符串,则返回-1
$isArray    确定操作数是否为数组,返回一个布尔值
$last    返回最后一个数组元素,区别于$last蓄能器
$map    将子表达式应用于数组的每个元素并按顺序返回结果值数组,接受命名参数
$objectToArray    将文档转换为表示键值对的文档数组
$range    根据用户定义的输入输出一个包含整数序列的数组
$reduce    将表达式应用于数组中的每个元素并将它们组合成一个值
$reverseArray    返回一个元素以相反顺序排列的数组
$size    返回数组中元素的数量,接受单个表达式作为参数
$slice    返回数组的子集
$zip    将两个数组合并在一起
*/

等等太多了,我们不可能全部都用到,用到的时候去官网查询即可,更重要的一点是我们最终都是通过程序去访问MongoDB。这些操作符一定会有相应的API对他们进行封装。

2.4、文档之间的关系

前面我们说MongoDB是最像关系型数据库的NoSQL,那么具体的体现在哪里呢?除了以上的操作符外,文档之间关联关系是最能体现关系型数据库的特性。

1、一对一(one to one)

// 文档之间 一对一关系 通过内嵌文档体现
use test;
db.marry.insert({"name": "杨过","girlFriend": {"name": "小龙女"}
});
db.marry.find().pretty();
// pretty() 数据在命令行中更加美观的显示,不至于太紧凑

2、一对多(one to many) / 多对一(many to one)

// 一对多的关系也可以使用内嵌文档映射一对多关系
// 例如用户与订单关系
{"_id": "01",username: "alex",pwd: "123",order: [{"_id": "222", guid: "xxx"},{"_id": "333", guid: "xxx"},]
}
// 两个集合之间的一对多关系
use test;
db.orderList.insert([{productName: "Iphone 13", userId: "62431618c35b0000b700440b"},{productName: "蓝牙耳机", userId: "62431618c35b0000b700440b"},
]);
var userId = db.userList.findOne({"name": "alex"})._id;
db.orderList.find({userId: userId});

3、多对多(many to many)

// 老师和学生就是多对多的典型例子
use test;
db.teacherList.insert([{"name": "雷神", "age": 18},{"name": "康师傅", "age": 20}
]);db.teacherList.find({});db.studentList.insert([{"name": "alex", teacherId: ["62495a221e0f0000f00006c2", "62495a221e0f0000f00006c3"]},{"name": "spring", teacherId: ["62495a221e0f0000f00006c2", "62495a221e0f0000f00006c3"]},
]);

2.5、结果集排序与分页

查询文档时,默认情况是按照 _id 的值进行升序排序的。

// sort(sort)方法 可以用来指定文档的排序规则,sort为一个对象用来声明排序规则
db.userList.find().sort({age: -1}); // -1降序 1升序


多级排序

// 如果age有相同的 则按照 _id 升序排序
db.userList.find().sort({age: -1, _id: 1});

分页在实际开发中也比较常见,为了加快查询速度都要考虑分页,那么在MongoDB中如何实现呢?

// 分页使用 limit() skip() 方法实现
// 计算公式为 skip((pageNo - 1) * pageSize).limit(pageSize);
// 例如每页返回5个文档,查询第2页// 为了查看方便给集合添加 rownum 字段
for (var i = 0; i < db.userList.count(); i++) {var user = db.userList.find()[i];user.rownum = i + 1;db.userList.update({"_id": user._id}, {$set: user});
}var pageNo = 2;
var pageSize = 5;
db.userList.find().skip((pageNo - 1) * pageSize).limit(pageSize);

3、SpringData集成MongoDB

3.1、SpringBoot完成交互

1、使用SpringBoot初始化向导创建一个maven工程

2、引入mongodb的场景启动器

<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-mongodb -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>

3、修改application.ymlapplication.properties配置文件

application.yml

spring:data:mongodb:host: 121.41.58.169username: rootpassword: lijianadatabase: testport: 27017authentication-database: test

4、编写测试交互方法

/*** @description:* @date: 2022/4/3 18:43*/
@SpringBootTest
public class MongoDBTest {@Autowiredprivate MongoTemplate mongoTemplate;@Testpublic void test() {// 在userList集合中查询name=java的文档Query query = Query.query(Criteria.where("name").is("java"));List<Map> mapList = mongoTemplate.find(query, Map.class, "userList");System.out.println(mapList);}
}

3.2、MongoTemplate的读写API

因为SpringBoot简便性,前面的集成工作很简单,重要的是我们要学会MongoTemplate操作数据库的API,这才是实际开发中最常用的。

为了让某些API知道我们操作的是那个集合,我们需要定义一个实体,这个实体通过@Document注解声明文档、实体、集合的映射关系。

/*** @description:* @date: 2022/4/3 19:26*/
@Document(collection = "userList") // 一定不要写成collation
public class UserVO {private String _id;private String name;private String pwd;private Integer age;private Integer rownum;...
}

1、查询

// 查询集合中所有的文档
@Test
public void find() {List<UserVO> userVOList = mongoTemplate.findAll(UserVO.class);// List<Map> userList = mongoTemplate.findAll(Map.class, "userList");System.out.println(userVOList);
}
// 结果集数量获取
@Test
public void count() {long count = mongoTemplate.count(Query.query(Criteria.where("")), UserVO.class); // 集合中所有文档数量// 筛选条件可以使用 Query.query(Criteria.where(key) 随机构造System.out.println(count);
}
// 查询多个并排序
@Test
public void sort() {Query query = Query.query(Criteria.where("name").is("python")).with(Sort.by(Sort.Order.desc("rownum"))); // 按rownum降序List<UserVO> userList = mongoTemplate.find(query, UserVO.class);userList.forEach(System.out :: println);
}
// 分页查询
@Test
public void limit() {Integer pageNo = 2; // 页码Integer pageSize = 5; // 每页展示的大小Pageable pageable = PageRequest.of((pageNo - 1), pageSize, Sort.by(Sort.Order.asc("rownum")));Query query = new Query().with(pageable);List<UserVO> userList = mongoTemplate.find(query, UserVO.class);userList.stream().forEach(user -> System.out.println("name=" + user.getName() + "/rownum=" + user.getRownum()));
}

2、添加

@Test
public void insert() {UserVO user = new UserVO();user.setName("娜宝贝");user.setAge(18);user.setPwd("456");user.setRownum(13);UserVO userVO = mongoTemplate.save(user);// UserVO userVO = mongoTemplate.save(user, "userList"); 指定集合名称保存System.out.println(userVO);// 保存多个List<UserVO> userVOList = new ArrayList<>();UserVO u1 = new UserVO("娜宝贝1", "@123", 20, 14);UserVO u2 = new UserVO("娜宝贝2", "@123", 20, 15);UserVO u3 = new UserVO("娜宝贝3", "@123", 18, 16);userVOList.add(u1);userVOList.add(u2);userVOList.add(u3);Collection<UserVO> insertList = mongoTemplate.insert(userVOList, UserVO.class);// Collection<UserVO> userList = mongoTemplate.insert(userVOList, "userList"); 指定集合名称进行保存
}

3、更新

@Test
public void update() {String id = "6249944d645c5a2fe14f0a6b";Update update = Update.update("name", "娜宝贝666").set("pwd", "@520").set("age", 23);UpdateResult result = mongoTemplate.updateFirst(Query.query(Criteria.where("_id").is(id)), update, UserVO.class);System.out.println(result);//mongoTemplate.updateMulti() 更新多个
}

4、删除数据就不用说了,实际开发中业务数据都是逻辑删除,不可能是物理删除。

当然我也不可能列出全部,使用到时自己写写例子,研究一下即可。

END

END

懒人数据库 MongoDB 5.x相关推荐

  1. wu-database-lazy-starter(懒人数据库操作-核心增量式更新)

    快速入门 简介 特性 强大的CRUD操作:内置通过注入 LazyLambdaStream 对象即可实现表单的大部分CRUD操作 支持Lambda形式的调用: 通过Lambda表达式,方便的编写各类查询 ...

  2. python scrapy+Mongodb爬取蜻蜓FM,酷我及懒人听书

    1.初衷:想在网上批量下载点听书.脱口秀之类,资源匮乏,大家可以一试 2.技术:wireshark scrapy jsonMonogoDB 3.思路:wireshark分析移动APP返回的各种连接分类 ...

  3. NoSQL数据库-MongoDB和Redis

    NoSQL数据库-MongoDB和Redis   发布于2012-12-20,来源:比特网   1NoSQL简述 CAP(Consistency,Availabiity,Partitiontolera ...

  4. 一个基于xml的超级orm框架-世界是由懒人创造的。

    这个题目好像有些过了,呵呵,不过,大抵是这样的,因为有懒人的存在,所以才会有世界的进步.从农耕社会开始,人们为了偷懒,而蓄野生动物,如狼牛等为已用,而成为牛狗,再耕地时牛便成为主力.扯得太远了.一时半 ...

  5. 懒人小工具1:winform自动生成Model,Insert,Select,Delete以及导出Excel的方法

       懒人小工具2:T4自动生成Model,Insert,Select,Delete以及导出Excel的方法    github地址:https://github.com/Jimmey-Jiang/J ...

  6. 公网访问阿里云数据库MongoDB——填坑笔记

    业务情景 两台服务器,一台阿里云ECS云服务器(专用网络),另一台是阿里云数据库MongoDB,处于安全考虑MongoDB是不运行外网连接的,那接下来就看怎么实现公网访问. 看到上面红色的网络类型描述 ...

  7. 手机电脑自适应导航源码php,自适应各终端懒人网址导航源码 v2.0

    自适应各终端懒人网址导航源码. V2.0版本是在原1.8版本的基础上修复和增加了些功能.推荐直接使用新版本,舍弃旧版本,后期会继续不定期更新. 测试环境: 宝塔Nginx -Tengine2.2.3的 ...

  8. 面向文档的NoSQL数据库MongoDB

    NoSQL优势 全称:Not Only SQL 不仅仅是数据库 海量的扩展能力 读写高性能 与关系型数据库(RDBMS)相辅相成 NoSQL产品 键值存储型(Key-Value) Redis/Codi ...

  9. 新手项目:黑马blog (适合刚接触node和数据库MongoDB)

    来源:黑马前端 难度:⭐⭐(基础)--的新适合刚接触node和数据库MongoDB手小白 所需知识: 第三方模块: express框架(用于创建网站服务器以及路由) moogoose(连接数据库和操作 ...

最新文章

  1. 来自程序员的福利!用Python做一款翻译软件
  2. 十、oracle 常用函数
  3. 【AOP 面向切面编程】Android Studio 使用 AspectJ 监控方法运行原理分析
  4. Android 应用程序之间内容分享详解(二)
  5. DL之RetinaNet:RetinaNet算法的简介(论文介绍)、架构详解、案例应用等配图集合之详细攻略
  6. 2021-06-14
  7. 强连通分量(Strongly_Connected_Components)
  8. php获取栏目文章总数,织梦DedeCMS获取当前栏目文章数量
  9. 如果没有网上购物,商铺价格会不会更高?
  10. sql2012一段时间无法连接报53错误
  11. 这就是你在妈妈肚子里尿尿的样子 | 今日最佳
  12. laravel 任务队列_laravel队列-让守护进程处理耗时任务
  13. Android 笔记
  14. R语言在大气污染数据分析中的应用-时间序列分析(一)
  15. 机器视觉之表面缺陷检测
  16. 广州宽带市场割喉战:电信地狱价小企业陷两难
  17. 华为小程序怎么弄出来_华为手机添加桌面小程序 华为手机小程序怎么弄出来...
  18. Mybatis批量插入数据到Oracel
  19. (转载)深入了解iOS中的OOM(低内存崩溃)
  20. 7.2 MVC 实现登录验证

热门文章

  1. Unity3D: 给字符串中的部分字体添加颜色突出显示
  2. 鸿蒙之主的武器,别具心意 全门派T8武器赏析
  3. spring boot(7)-mybatis全注解化
  4. 学习是一种态度,优秀是一种习惯
  5. 【openh264】libfreerdp 编解码 CQP VBR
  6. Oracle的授权方式
  7. [web] request的Content-Type小结
  8. 全网最硬核 JVM TLAB 分析 6. TLAB 相关热门QA汇总
  9. 【面试】小米公司嵌入式职位面试经验
  10. 小米公司在互联网的地位怎么样