• MongoDB入门学习(一)


    1. 简介

    1.1 NoSQL和MongoDB

    NoSQL与SQL的区别:

    • SQL(关系型数据库)
      • 关系型网格充分的体现了现实事务。
        一般由rows、columns组成tables,而各个tables之间又存在一定的关系Relations
        一个table包含着另一个和他有关系的数据比如说teams和players表中就存在这种关系。
      • 语句遵循SQL(Structured Query Language)例如
        SELECT FROM players WHERE last name “yzzy”;
    • NoSQL
      • 没有关系
      • 不支持SQL
      • 查询数据手段多样,比如Http,JavaScript来查询

    1.2 MongoDB特点

    • 灵活易于扩展
    • 分布式文档数据库
    • 支持json与bson格式
    • 使用JavaScripti语句
    • 事务的ACID

    1.2.1 MongoDB 技术优势

    MongoDB基于灵活的JSON文档模型(从错综复杂的关系模型到对象模型)。适合敏捷开发,能快速响应业务变化。其高可用(自恢复、多中心容灾能力)、高水平扩展能力(横向无缝扩展,多种数据分布策略,分片,TB-PB级别)使得在处理海量、高并发的数据应用时颇具优势。

    1.2.2 Json 模型快速特性

    • 数据库引擎只需要写在一个存储区
    • 反范式、无关联的组织极大优化查询速度
    • 程序API自然,开发快速

    1.3 MongoDB 应用场景

    游戏(积分、装备);物流(订单);社交(朋友圈、地点、附近的人);物联网(设备信息、日志);视频直播(用户信息、礼物);大数据;CRM、ERP
    在这里插入图片描述

    1.4 MongoDB与MongoDB Tool安装

    Mongo安装

    • 下载网址https:/www.mongodb.com/try/download/community
      windows下载msi,其他操作系统可以参考文档
    • 安装时注意
      Data Directory:数据存放的路径;Log Dirctory:日志存放的路径;MongoDB Compass(界面化数据库管理工具)建议安装
      检测安装是否成功WIN+R输入“services.msc"指令查看是否服务启动

    1.5 MongoDB数据导入导出

    导入

    命令:mongoimport --db dbname --type json xxx.json(也可以是jsonArray的形式导入)
    示例:mongoimport --db test_db --type json product.json
    以下是 products.json 文件

    { "_id" : "ac3", "name" : "AC3 Phone", "brand" : "ACME", "type" : "phone", "price" : 200, "rating" : 3.8,"warranty_years" : 1, "available" : true }
    { "_id" : "ac7", "name" : "AC7 Phone", "brand" : "ACME", "type" : "phone", "price" : 320, "rating" : 4,"warranty_years" : 1, "available" : false }
    { "_id" : { "$oid" : "507d95d5719dbef170f15bf9" }, "name" : "AC3 Series Charger", "type" : [ "accessory", "charger" ], "price" : 19, "rating" : 2.8,"warranty_years" : 0.25, "for" : [ "ac3", "ac7", "ac9" ] }
    { "_id" : { "$oid" : "507d95d5719dbef170f15bfa" }, "name" : "AC3 Case Green", "type" : [ "accessory", "case" ], "color" : "green", "price" : 12, "rating" : 1,"warranty_years" : 0 }
    { "_id" : { "$oid" : "507d95d5719dbef170f15bfb" }, "name" : "Phone Extended Warranty", "type" : "warranty", "price" : 38, "rating" : 5,"warranty_years" : 2, "for" : [ "ac3", "ac7", "ac9", "qp7", "qp8", "qp9" ] }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    导出

    命令:mongoexport -d dbname -c collectionname -o filepath --type json/csv -f field
    示例:mongoexport -d test_db -products -o pro.json

    2. MongoDB 基本操作

    2.1 MongoDB创建数据

    查看有那些数据库show dbs
    获取当前数据库的名称
    创建数据库use db name
    创建一个Collections Document
    db.cool_new_stff.insertOne()db.cool.new.stff.insertOne()

    show dbs
    	admin    180.00 KiB
    	config    72.00 KiB
    	local     72.00 KiB
    	test_db  232.00 KiB
    show databases
    	admin    180.00 KiB
    	config    72.00 KiB
    	local     72.00 KiB
    	test_db  232.00 KiB
    use example
    	'switched to db example'
    doc = {"title":"A","desc":"demo"}
    	{ title: 'A', desc: 'demo' }
    db.name.insertOne(doc);
    	{ acknowledged: true,
    	  insertedId: ObjectId("6357ed0001c87366b1808a96") }
    db.name.insertOne(doc);
    	{ acknowledged: true,
    	  insertedId: ObjectId("6357ed0001c87366b1808a96") }
    db.cool_new_stff.insertOne({});
    	{ acknowledged: true,
    	  insertedId: ObjectId("6357ee6601c87366b1808a97") }
    db.cool.new.stff.insertOne({});
    	{ acknowledged: true,
    	  insertedId: ObjectId("6357ee7f01c87366b1808a98") }
    show collections
    	cool_new_stff
    	cool.new.stff
    	name
    
    • 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

    2.2 Collections简介与基础操作

    1. 清屏cls
    2. 切换到数据库查找

    查找所有:db.products.find()
    查找类型等于’service’的:db.products.find({“type”:“service”});
    格式化显示:db.products.find({“type”:“service”}).pretty();
    只展示type该字段:db.products.find({),{“type”:1});
    db.products.find({“type”:“service”),{“type”:1}).pretty();
    支持正则表达式
    db.products.find({“name”:{$regex:/phone/i}})
    db.products.find({“name”:{Sregex:/phone/i)),{“type”:1))

    db.name.find()
    { _id: ObjectId("6357ed0001c87366b1808a96"), title: 'A', desc: 'demo' }
    { _id: ObjectId("6357f15101c87366b1808a9c"), type: 123 }
    { _id: ObjectId("6357f17e01c87366b1808a9e"), name: 'Huathy' }
    db.name.find({"type":"1"})
    db.name.find({"type":1})
    db.name.find({"type":123})
    { _id: ObjectId("6357f15101c87366b1808a9c"), type: 123 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    3. Query

    3.1 Limit 与 Count

    db.name.find({"title":"A"}).count()
    	4
    db.name.find({"title":"A"}).limit(2)
    	{ _id: ObjectId("6357ed0001c87366b1808a96"),
    	  title: 'A',
    	  desc: 'demo' }
    	{ _id: ObjectId("6357f13001c87366b1808a99"),
    	  title: 'A',
    	  desc: 'demo' }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    3.2 Sort 与 Skip

    注意:skip()对于count()无效。也就是说不论是否跳过,统计总数都不变。

    db.names.find()
    	{ _id: ObjectId("63593ffb2108eeaab632e0d8"), num: 11 }
    	{ _id: ObjectId("635940002108eeaab632e0d9"), num: 22 }
    	{ _id: ObjectId("635940032108eeaab632e0da"), num: 33 }
    db.names.find().sort({"num":1})
    	{ _id: ObjectId("63593ffb2108eeaab632e0d8"), num: 11 }
    	{ _id: ObjectId("635940002108eeaab632e0d9"), num: 22 }
    	{ _id: ObjectId("635940032108eeaab632e0da"), num: 33 }
    db.names.find().sort({"num":-1})
    	{ _id: ObjectId("635940032108eeaab632e0da"), num: 33 }
    	{ _id: ObjectId("635940002108eeaab632e0d9"), num: 22 }
    	{ _id: ObjectId("63593ffb2108eeaab632e0d8"), num: 11 }
    db.names.find().sort({"num":-1}).skip(2)
    	{ _id: ObjectId("63593ffb2108eeaab632e0d8"), num: 11 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    3.3 $gt$lt

    注意:大于小于比较的前提是有该字段,如果没有这个字段的记录,则不会被查询出来。(这里建议设置collections的标准)

    db.names.find()
    	{ _id: ObjectId("63593ffb2108eeaab632e0d8"), num: 11 }
    	{ _id: ObjectId("635940002108eeaab632e0d9"), num: 22 }
    	{ _id: ObjectId("635940032108eeaab632e0da"), num: 33 }
    	{ _id: ObjectId("635940082108eeaab632e0db"), num: 44 }
    	{ _id: ObjectId("6359400c2108eeaab632e0dc"), num: 55 }
    	{ _id: ObjectId("635942d72108eeaab632e0dd"), name: 'Huathy' }
    db.names.find({"num":{$gt:33}})
    	{ _id: ObjectId("635940082108eeaab632e0db"), num: 44 }
    	{ _id: ObjectId("6359400c2108eeaab632e0dc"), num: 55 }
    db.names.find({"num":{$lt:33}})
    	{ _id: ObjectId("63593ffb2108eeaab632e0d8"), num: 11 }
    	{ _id: ObjectId("635940002108eeaab632e0d9"), num: 22 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3.4 $or(或)、$and(并)、$all(全)、$in(有)

    3.4.1 $or(或)、$and(并)

    db.prod.find({$or:[{"price":{$lt:100}},{"rating":{$gt:3}}]});
    	{ _id: ObjectId("63594a882108eeaab632e0de"),
    	  price: 55,
    	  rating: 1 }
    	{ _id: ObjectId("63594a8c2108eeaab632e0df"),
    	  price: 55,
    	  rating: 2 }
    	{ _id: ObjectId("63594a902108eeaab632e0e0"),
    	  price: 55,
    	  rating: 3 }
    	{ _id: ObjectId("63594aa02108eeaab632e0e2"),
    	  price: 205,
    	  rating: 4 }
    db.prod.find({$and:[{"price":{$lt:100}},{"rating":{$gt:2}}]});
    	{ _id: ObjectId("63594a902108eeaab632e0e0"),
    	  price: 55,
    	  rating: 3 }
    db.prod.find({$and:[{"price":{$lt:100}},{"rating":{$gt:2}}]}).count();
    	1
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.4.2 $all(全)、$in(有)

    -- 所有都要满足
    db.prod.find({"price":{$all:[55,100]}});
    	{ _id: ObjectId("635c000507b9962cd04d608f"),
    	  price: [ 55, 100 ] }
    -- 满足条件之一即可
    db.prod.find({"price":{$in:[55,105]}});
    	{ _id: ObjectId("63594a882108eeaab632e0de"),
    	  price: 55,
    	  rating: 1 }
    	{ _id: ObjectId("63594a962108eeaab632e0e1"),
    	  price: 105,
    	  rating: 3 }
        { _id: ObjectId("635c000507b9962cd04d608f"),
     	  price: [ 55, 100 ] }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4. 修改数据

    update修改所有;updateOne修改一个

    4.1 字符操作

    4.1.1 $set 修改

    db.prod.find()
    	{ _id: ObjectId("63594aa02108eeaab632e0e2"),
    	  price: 205,
    	  rating: 4 }
    	  -- 条件属性和值 设置 修改的属性和值
    db.prod.updateOne({"rating":4},{$set:{"price":100}})
    	{ acknowledged: true,
    	  insertedId: null,
    	  matchedCount: 1,
    	  modifiedCount: 1,
    	  upsertedCount: 0 }
    db.prod.find()
    	{ _id: ObjectId("63594aa02108eeaab632e0e2"),
    	  price: 100,
    	  rating: 4 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.1.2 $unset 删除字段

    db.prod.updateOne({"rating":4},{$unset:{"price":1}})
    	{ acknowledged: true,
    	  insertedId: null,
    	  matchedCount: 1,
    	  modifiedCount: 1,
    	  upsertedCount: 0 }
    db.prod.find()
    	{ _id: ObjectId("63594aa02108eeaab632e0e2"), rating: 4 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    4.1.3 $inc 增加

    db.prod.updateOne({"rating":4},{$inc:{"price":1000}})
    	{ acknowledged: true,
    	  insertedId: null,
    	  matchedCount: 1,
    	  modifiedCount: 1,
    	  upsertedCount: 0 }
    db.prod.find()
    	{ _id: ObjectId("63594aa02108eeaab632e0e2"),
    	  rating: 4,
    	  price: 1000 }
    -- 如果再次执行操作,则会再次增加
    db.prod.updateOne({"rating":4},{$inc:{"price":1000}})
    db.prod.find()
    { _id: ObjectId("63594aa02108eeaab632e0e2"),
      rating: 4,
      price: 2000 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4.2 Arrays : $push $pull 增加 / 移除

    4.2.1 $push

    db.prod.find()
    	{ _id: ObjectId("635c000507b9962cd04d608f"),
    	  price: [ 55, 100 ],
    	  rating: 5 } 
    db.prod.updateOne({"rating":5},{$push:{"price":1000}})
    	{ acknowledged: true,
    	  insertedId: null,
    	  matchedCount: 1,
    	  modifiedCount: 1,
    	  upsertedCount: 0 }
    db.prod.find()
    	  { _id: ObjectId("635c000507b9962cd04d608f"),
    	  price: [ 55, 100, 1000 ],
    	  rating: 5 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.3 delete

    1. 尽量少删除元素,而是采用逻辑删除,用deleted字段来标识。
    2. delete删除所有,deleteOne删除一个
    3. 建议按照_id来删除元素。
    db.prod.deleteOne({"_id":"63594a8c2108eeaab632e0df"})
    	{ acknowledged: true, deletedCount: 0 }
    db.prod.find({"_id":"63594a8c2108eeaab632e0df"})
    
    • 1
    • 2
    • 3

    5、MongoDB整合SpringBoot集合操作

    5.1 环境准备

    1. 引入依赖
    <dependency>
      <groupId>org.springframework.bootgroupId>
      <artifactId>spring-boot-starter-data-mongodbartifactId>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    1. 配置yml
    spring:
        data:
          mongodb:
              uri: mongodb://admin:123456@172.25.196.210:27017/example?authSource=admin
    
    • 1
    • 2
    • 3
    • 4
    1. 使用的时候注入mongoTemplate
    @Autowired
    private MongoTemplate mongoTemplate;
    
    • 1
    • 2

    5.2 集合操作

    public class MongoTest1 extends ApplicationTests{
        @Autowired
        private MongoTemplate mongoTemplate;
        /**
         * 创建集合
         */
        @Test
        public void test_create(){
            boolean exists = mongoTemplate.collectionExists("emp");
            if(exists){
                mongoTemplate.dropCollection("emp");
            }
            mongoTemplate.createCollection("emp");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    6、MongoDB整合SpringBoot文档操作

    6.1 文档操作-相关注解

    1. @Document
      • 修饰范围:Class类
      • 作用:用来映射这个类的一个对象为mongo中的一条文档数据
      • 属性:(value、collection)用来指定操作的集合
    2. @Id
      • 修饰范围:成员变量、方法
      • 作用:用来将成员变量的值映射为文档的_id的值
    3. @Id
      • 修饰范围:成员变量、方法
      • 作用:将成员变量及其值,映射为文档中的一个Key:Value对。
      • 属性:(name、value)用来指定在文档中key的名称,默认为成员变量名
    4. @Transient
      • 修饰范围:成员变量、方法
      • 作用:指定此成员变量不参与文档序列号

    测试:

    @Test
    public void test_insert() {
       Employee employee = new Employee(1001, "Huathy", 20, 10000.0, new Date());
       Employee emp1 = mongoTemplate.insert(employee);
       System.out.println("TEST 1 ==> " + emp1.toString());
       Employee emp2 = mongoTemplate.save(employee);
       System.out.println("TEST 2 ==> " + emp2.toString());
       List<Employee> list = Arrays.asList(
               new Employee(1002, "嘻嘻", 20, 20000.0, new Date()),
               new Employee(1003, "嘿嘿", 20, 30000.0, new Date())
       );
       Collection<Employee> coll = mongoTemplate.insert(list, Employee.class);
       coll.forEach(c -> {
           System.out.println("COLL INSERT ==> " + c.toString());
       });
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    在这里插入图片描述注意:通过SpringDataMongoDB还会给集合中增加一个class属性,存储新增时Document对应Java中类的全路径。这么做是为了查询的时候能够把Doucument转为Java类型。

    6.2 查询文档

    Criteria是标准查询的接口。可以引用静态的Criteria.where把多个条件组合到一起,就可以轻松的将多个方法标准和查询条件相结合,方便查询语句操作。

    CriteriaMongoDB说明
    and$and并且
    andOperator$and并且
    orOperator$or或者
    gt$gt大于
    gte$gte大于等于
    in$in包含
    is$is等于
    lt$lt小于
    lte$lte小于等于
    nin$nin不包含

    测试:

    /**
     * 查询与条件查询
     */
    @Test
    public void test_find() {
        System.out.println("==============查询所有文档=================");
        List<Employee> allemps = mongoTemplate.findAll(Employee.class);
        List<Employee> allemps2 = mongoTemplate.find(new Query(), Employee.class);
        allemps.forEach(e -> {
            System.out.println(e.toString());
        });
    
        System.out.println("============根据_id查询===================");
        Employee emp1 = mongoTemplate.findById(1001, Employee.class);
        System.out.println("findByID ==> " + emp1.toString());
    
        System.out.println("============findOne返回第一个文档===================");
        Employee emp2 = mongoTemplate.findOne(new Query(), Employee.class);
        System.out.println("findOne ==> " + emp2.toString());
    
        System.out.println("============find 单 条件查询===================");
        Query query = new Query(Criteria.where("salary").gt(6000).lte(10000));
        List<Employee> emps3 = mongoTemplate.find(query, Employee.class);
        emps3.forEach(e -> {
            System.out.println("find ==> " + e.toString());
        });
    
        System.out.println("============find 多 条件查询===================");
        Criteria criteria = new Criteria();
        criteria.orOperator(Criteria.where("salary").gt(6000).lte(10000), Criteria.where("name").regex("嘻"));
        List<Employee> emps4 = mongoTemplate.find(new Query(criteria), Employee.class);
        emps4.forEach(e -> {
            System.out.println("find ==> " + e.toString());
        });
    }
    
    /**
     * 排序与分页
     */
    @Test
    public void test_sort() {
        System.out.println("============ sort ===================");
        Query query = new Query();
        query.with(Sort.by(Sort.Order.desc("salary")));
        List<Employee> emps = mongoTemplate.find(query, Employee.class);
        emps.forEach(e -> {
            System.out.println("order find ==> " + e.toString());
        });
        System.out.println("============ page ===================");
        // skip limit 分页。skip跳过记录数、limit限定返回结果数
        Query query1 = new Query();
        query1.with(Sort.by(Sort.Order.desc("salary"))).skip(0).limit(1);
        List<Employee> emps1 = mongoTemplate.find(query1, Employee.class);
        emps1.forEach(e -> {
            System.out.println("limit find ==> " + e.toString());
        });
    }
    
    @Test
    public void test_findByJson() {
        System.out.println("========等值查询=========");
        String eqJson = "{name:'Huathy'}";
        Query query1 = new BasicQuery(eqJson);
        List<Employee> emps1 = mongoTemplate.find(query1, Employee.class);
        emps1.forEach(System.out::println);
        System.out.println("========多条件查询=========");
        String json = "{ $or:[{age:{$gte:22}},{salary:{$gt:10000}}] }";
        Query query = new BasicQuery(json);
        List<Employee> emps = mongoTemplate.find(query, Employee.class);
        emps.forEach(System.out::println);
    }
    
    • 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
    • 68
    • 69
    • 70
    • 71

    6.3 更新文档

    在MongoDB中无论使用客户端API还是使用SpringData,更新返回结果一定是受影响行数。若更新后的结果与更新前的结果相同,则返回0;

    • updateFirst():只更新满足条件的第一条记录
    • updateMulti():更新所有满足条件的记录
    • upsert():没有符合条件的记录则插入一条数据

    测试:

    @Test
    public void test_update(){
        Query query = new Query(Criteria.where("salary").is(10000));
        List<Employee> emps = mongoTemplate.find(query, Employee.class);
        System.out.println("=========== 更新前 ==========");
        emps.forEach(System.out::println);
        Update update = new Update();
        update.set("salary",12000);
        UpdateResult res1 = mongoTemplate.updateFirst(query, update, Employee.class);
        System.out.println("更新成功记录数1 => " + res1);
        UpdateResult res2 = mongoTemplate.updateMulti(query, update, Employee.class);
        System.out.println("更新成功记录数2 => " + res2);
    
        Query query1 = new Query(Criteria.where("salary").is(50000));
        List<Employee> emps1 = mongoTemplate.find(query1, Employee.class);
        emps1.forEach(System.out::println);
        System.out.println("=========== 更新前 ==========");
        UpdateResult res3 = mongoTemplate.upsert(query, update, Employee.class);
        System.out.println("更新成功记录数3 => " + res3);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    6.4 删除操作

    测试:

    @Test
    public void test_delete(){
    //        删除所有文档   // 不如使用dorpCollection()
    //        mongoTemplate.remove(new Query(),Employee.class);
       Query query = new Query(Criteria.where("salary").is(12000));
       DeleteResult res = mongoTemplate.remove(query, Employee.class);
       System.out.println("删除记录数 => " + res);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
  • 相关阅读:
    大咖说*每周推荐 | 云采销助力中小企业获客提升 300%
    Spring Cloud Sleuth 整合 Zipkin 进行服务链路追踪
    MATLAB图像处理介绍
    Android app专项测试之耗电量测试
    [HDLBits] Exams/review2015 count1k
    浅谈Array --JavaScript内置对象
    【C++】 对象模型与内存模型的区别
    预计2023年交付35万台,增速超400%!HUD硬核玩家强势崛起
    java程序员必会-远程debug
    轻量级简约仪表板Dasherr
  • 原文地址:https://blog.csdn.net/qq_40366738/article/details/127475763