博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
MySQL、MongoDB、Redis 数据库之间的区别与使用(本章迭代更新)
阅读量:4983 次
发布时间:2019-06-12

本文共 15289 字,大约阅读时间需要 50 分钟。

MySQL、MongoDB、Redis 数据库之间的区别与使用

MySQL、MongoDB、Redis 数据库之间的区别与使用(本章迭代更新)

update:2019年2月20日 15:21:19(本章迭代更新)


一.数据库之间的区别

MySQL

MySQL概述

关系型数据库。无论数据还是索引都存放在硬盘中。到要使用的时候才交换到内存中。能够处理远超过内存总量的数据。

在不同的引擎上有不同 的存储方式。
查询语句是使用传统的 SQL 语句,拥有较为成熟的体系,成熟度很高。
开源数据库的份额在不断增加,MySQL 的份额页在持续增长。
缺点:在海量数据处理的时候效率会显著变慢。

MySQL特点

  1. 使用c和c++编写,并使用了多种编译器进行测试,保证源代码的可移植性
  2. 支持多种操作系统
  3. 为多种编程语言提供可API
  4. 支持多线程,充分利用CPU资源优化的SQL查询算法,有效的提高查询速度
  5. 提供多语言支持,常见的编码如:GB2312、BIG5、UTF8
  6. 提供TCP/IP、ODBC和JDBC等多种数据库连接途径提供用于管理、检查、优化数据库操作的管理工具
  7. 大型的数据库。可以处理拥有上千万条记录的大型数据库
  8. 支持多种存储引擎
  9. MySQL软件采用了双授权政策,分为社区版和商业版,由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,一般中小型网站的开发都选择MySQL作为网站数据库
  10. MySQL使用标准的SQL数据语言形式
  11. Mysql是可以定制的,采用GPL协议,你可以修改源码来开发自己的MySQL系统
  12. 在线DDL更改功能
  13. 复制全局事务标识
  14. 复制无崩溃从机
  15. 复制多线程从机

MongoDB

MongoDB概述

它是一个内存数据库,数据都是放在内存里面的。

对数据的操作大部分都在内存中,但 MongoDB 并不是单纯的内存数据库。
MongoDB 是由 C++ 语言编写的,是一个基于分布式文件存储的开源数据库系统。
在高负载的情况下,添加更多的节点,可以保证服务器性能。
MongoDB 旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
缺点:占用的空间很大

MongoDB特点

  1. 模式自由:可以把不同结构的文档存储在同一个数据库里
  2. 面向集合的存储:适合存储JSON风格文件的形式
  3. 完整的索引支持,对任何属性可索引
  4. 复制和高可用性:支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目的是提供冗余及自动故障转移
  5. 自动分片:支持水平的数据库集群,可动态添加额外的机器
  6. 丰富的查询:支持丰富的查询表达方式,查询指令使用JSON形式额标记,可轻易查询文档中的内嵌的对象及数组
  7. 快速就地更新:查询优化器会分析查询表达式,并生成一个高效的查询计划
  8. 高效的传统存储方式:支持二进制数据及大型对象

Redis

Redis概述

它就是一个不折不扣的内存数据库。

持久化方式:Redis 所有数据都是放在内存中的,持久化是使用 RDB 方式或者 aof 方式。

Redis特点

  1. Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
  2. Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,在set,hash等数据结构的存储。
  3. Redis支持数据的备份,即master-slave模式的数据备份
  4. 性能极高- Redis能读的速度是110000次/s,写的速度是81000次/s
  5. 丰富的数据类型-Redis支持二进制案例的Strings,Lists,Hashes,Setes及Ordered Sets数据类型操作。
  6. 原子 - Redis的所有操作都是原子性的,同时Redis还支持对几个操作全并后的原子性执行。
  7. 丰富的特性 - Redis还支持publish/subscribe,通知,key过期等等特性。

性能区分

* 当物理内存够用的时候,Redis > MongoDB > MySQL* 当物理内存不够用的时候,Redis 和 MongoDB 都会使用虚拟内存。

实际上如果Redis要开始虚拟内存,那很明显要么加内存条,要么你就该换个数据库了。

但是,MongoDB 不一样,只要,业务上能保证,冷热数据的读写比,使得热数据在物理内存中,mmap 的交换较少。
MongoDB 还是能够保证性能。有人使用 MongoDB 存储了上T的数据。
MySQL,MySQL根本就不需要担心数据量跟内存下的关系。不过,内存的量跟热数据的关系会极大地影响性能表现。
当物理内存和虚拟内存都不够用的时候,估计除了 MySQL 你没什么好选择了。
其实,从数据存储原理来看,更倾向于将 MongoDB 归类为硬盘数据库,但是使用了 mmap 作为加速的手段而已。

使用场景分类

MySQL适用

  • 高度事务性的系统。例如银行或者会计系统,传统的关系型数据库目前还是更实用于需要大量原子性复杂事务的应用程序传统的商业智能应用,针对特定问题的BI数据库会对产生高度优化的查询方式,对于此类应用,数据仓库可能是更合适的选择

MongoDB适用

  • 网站数据:适合实时的插入,更新与查询,并具备网站实时数据存储所需对的复制及高度伸缩性;
  • 缓存:由于性能很高,也适合作为信息基础设施的缓存层,在系统重启之后,搭建的持久化缓存可以避免下层的数据源过载;
  • 大尺寸、低价值的数据也是MongoDB的最佳选择,使用传统的关系数据库存储一些数据时可能会比较贵,再次之前很多程序员往往会选择传统的文件进行存储
  • 高伸缩的场景,非常是个由数十或者数百台服务器组成的数据库
  • 用于对象及json数据的存储,MongoDB的bson数据格式非常适合文档格式化的存储及查询。

Redis适用

  • 用来做缓存-redis的所有数据时放在内存中的
  • 可以在某些特定应用场景下替代传统数据库--比如社交类的应用
  • 在一些大型系统中,巧妙的实现一些特定的功能:session共享、购物车

PS:

MongoDB和Redis都是NoSQL,采用结构型数据存储。二者在使用场景中,存在一定的区别,这也主要由于二者在内存映射的处理过程,持久化的处理方法不同。
MongoDB建议集群部署,更多的考虑到集群方案,Redis更偏重于进程顺序写入,虽然支持集群,也仅限于主-从模式。


简说mmap:

mmap系统调用并不是完全为了用于共享内存而设计的。它本身提供了不同于一般对普通文件的访问方式,进程可以像读写内存一样对普通文件进行操作。
mmap 系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后,进程可以像访问普通内存一样对文件进行访问,不必再调用。 read(),write()等操作。mmap并不分配空间, 只是将文件映射到调用进程的地址空间里, 然后你就可以用memcpy等操作写文件, 而不用write()了.写完后用msync()同步一下, 你所写的内容就保存到文件里了. 不过这种方式没办法增加文件的长度, 因为要映射的长度在调用mmap()的时候就决定了。


二.安装方式

PS:三种数据库均在Ubuntu中安装(Linux版)

1. 安装MySQL(非常简单)

[root@BenLam-vm_0 ~]# sudo apt-get install mysql-server[root@BenLam-vm_0 ~]# sudo apt-get isntall mysql-client[root@BenLam-vm_0 ~]# sudo apt-get install libmysqlclient-dev

2. 安装Mongodb

官网地址:

mongodb

下载 mongodb 安装包解压文件

[root@BenLam-vm_0 ~]# sudo tar -zxvf 下载目录 -C 解压目录

在解压目录下,新建一个目录data作为数据存储,在data下创建db和log两个目录

# 例如:mongodb所在目录为:/usr/database/mongodb[root@BenLam-vm_0 ~]# cd /usr/database/mongodb[root@BenLam-vm_0 ~]# mkdir data[root@BenLam-vm_0 ~]# cd data[root@BenLam-vm_0 ~]# mkdir db[root@BenLam-vm_0 ~]# mkdir log

启动服务器端

# 进入到/mongodb/bin 目录下,执行:[root@BenLam-vm_0 ~]# sudo ./mongod -dbpath=/usr/database/mongodb/data/db

见到如下信息说明启动成功:

mongodb

3. 安装Redis

官网地址:

mongodb
下载Redis 5.0 安装包解压文件

[root@BenLam-vm_0 ~]# sudo tar -zxvf 下载目录 -C 解压目录

进入解压目录,编译安装 redis

[root@BenLam-vm_0 ~]# sudo make && make install

进入src路径下,启动服务

[root@BenLam-vm_0 ~]# ./redis-server

mongodb

进入src路径下,启动客户端

[root@BenLam-vm_0 ~]# ./redis-cli

三.数据库日常使用

1. MySQL

MySQL 教程:直达链接

2. MongoDB

MongoDB 教程:直达链接

2.1 MongoDB命令帮助系统

在安装MongoDB后,启动服务器进程(mongod),可以通过在客户端命令mongo实现对MongoDB的管理和监控。看一下MongoDB的命令帮助系统:

[root@BenLam-vm_0 ~]# ./mongod -dbpath=/usr/database/mongodb/data/dbMongoDB shell version: 4.0.6connecting to: testWelcome to the MongoDB shell.For interactive help, type "help".For more comprehensive documentation, see    http://docs.mongodb.org/Questions? Try the support group    http://groups.google.com/group/mongodb-userServer has startup warnings:2018-02-20T23:24:23.304+0000 I CONTROL  [initandlisten] ** WARNING: You are running this process as the root user, which is not recommended.2018-02-20T23:24:23.304+0000 I CONTROL  [initandlisten]2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten]2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten]2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten] **        We suggest setting it to 'never'2018-02-20T23:24:23.307+0000 I CONTROL  [initandlisten]> help    db.help()                    help on db methods    db.mycoll.help()             help on collection methods    sh.help()                    sharding helpers    rs.help()                    replica set helpers    help admin                   administrative help    help connect                 connecting to a db help    help keys                    key shortcuts    help misc                    misc things to know    help mr                      mapreduce     show dbs                     show database names    show collections             show collections in current database    show users                   show users in current database    show profile                 show most recent system.profile entries with time >= 1ms    show logs                    show the accessible logger names    show log [name]              prints out the last segment of log in memory, 'global' is default    use 
set current database db.foo.find() list objects in collection foo db.foo.find( { a : 1 } ) list objects in foo where a == 1 it result of the last line evaluated; use to further iterate DBQuery.shellBatchSize = x set default number of items to display on shell exit quit the mongo shell>

这是MongoDB最顶层的命令列表,主要告诉我们管理数据库相关的一些抽象的范畴:数据库操作帮助、集合操作帮助、管理帮助。如果你想了解数据库操作更详细的帮助命令,可以直接使用db.help(),如下所示:

> db.help() DB methods:    db.adminCommand(nameOrDocument) - switches to 'admin' db, and runs command [ just calls db.runCommand(...) ]    db.auth(username, password)    db.cloneDatabase(fromhost)    db.commandHelp(name) returns the help for the command    db.copyDatabase(fromdb, todb, fromhost)    db.createCollection(name, { size : ..., capped : ..., max : ... } )    db.createUser(userDocument)    db.currentOp() displays currently executing operations in the db    db.dropDatabase()    db.eval() - deprecated    db.fsyncLock() flush data to disk and lock server for backups    db.fsyncUnlock() unlocks server following a db.fsyncLock()    db.getCollection(cname) same as db['cname'] or db.cname    db.getCollectionInfos()    db.getCollectionNames()    db.getLastError() - just returns the err msg string    db.getLastErrorObj() - return full status object    db.getLogComponents()    db.getMongo() get the server connection object    db.getMongo().setSlaveOk() allow queries on a replication slave server    db.getName()    db.getPrevError()    db.getProfilingLevel() - deprecated    db.getProfilingStatus() - returns if profiling is on and slow threshold    db.getReplicationInfo()    db.getSiblingDB(name) get the db at the same server as this one    db.getWriteConcern() - returns the write concern used for any operations on this db, inherited from server object if set    db.hostInfo() get details about the server's host    db.isMaster() check replica primary status    db.killOp(opid) kills the current operation in the db    db.listCommands() lists all the db commands    db.loadServerScripts() loads all the scripts in db.system.js    db.logout()    db.printCollectionStats()    db.printReplicationInfo()    db.printShardingStatus()    db.printSlaveReplicationInfo()    db.dropUser(username)    db.repairDatabase()    db.resetError()    db.runCommand(cmdObj) run a database command.  if cmdObj is a string, turns it into { cmdObj : 1 }    db.serverStatus()    db.setLogLevel(level,
) db.setProfilingLevel(level,
) 0=off 1=slow 2=all db.setWriteConcern(
) - sets the write concern for writes to the db db.unsetWriteConcern(
) - unsets the write concern for writes to the db db.setVerboseShell(flag) display extra information in shell output db.shutdownServer() db.stats() db.version() current version of the server

2.2 MongoDB基本命令

  1. show dbs

    显示当前数据库服务器上的数据库

  2. use pagedb

    切换到指定数据库pagedb的上下文,可以在此上下文中管理pagedb数据库以及其中的集合等

  3. show collections

    显示数据库中所有的集合(collection)

  4. db.serverStatus()

    查看数据库服务器的状态。
    有时,通过查看数据库服务器的状态,可以判断数据库是否存在问题,如果有问题,如数据损坏,可以及时执行修复。

  5. 查询指定数据库统计信息

    use fragment
    db.stats()
    查询结果示例如下所示:

> use fragmentswitched to db fragment> db.stats(){    "db" : "fragment",    "collections" : 0,    "objects" : 0,    "avgObjSize" : 0,    "dataSize" : 0,    "storageSize" : 0,    "numExtents" : 0,    "indexes" : 0,    "indexSize" : 0,    "fileSize" : 0,    "ok" : 1}
  1. 查询指定数据库包含的集合名称列表
> db.getCollectionNames() [         "17u",         "baseSe",         "bytravel",         "daodao",         "go2eu",         "lotour",         "lvping",         "mafengwo",         "sina",         "sohu",         "system.indexes" ]

2.3 基本DDL和DML

  1. 创建数据库
> show dbs local  0.078GB> use LuceneIndexDB switched to db LuceneIndexDB> show dbslocal  0.078GB> dbLuceneIndexDB> db.storeCollection.save({'version':'3.5', 'segment':'e3ol6'})WriteResult({ "nInserted" : 1 })> show dbsLuceneIndexDB  0.078GBlocal          0.078GB>
  1. 删除数据库

直接使用db.dropDatabase()即可删除数据库。

  1. 创建集合
> db.createCollection('replicationColletion', {'capped':true, 'size':10240, 'max':17855200}){ "ok" : 1 }> show collections replicationColletionstoreCollectionsystem.indexes
  1. 删除集合

    删除集合,可以执行db.mycoll.drop()。

  2. 插入更新记录

> db.storeCollection.save({'version':'0.1', 'segment':'66666'})WriteResult({ "nInserted" : 1 })
  1. 查询一条记录
> db.storeCollection.findOne({'version':'0.1'}) {    "_id" : ObjectId(".........."), # _id 是 MongoDB 自动生成的一段 ObjectId 值    "version" : "0.1",    "segment" : "66666"}
  1. 查询多条记录
    使用find()函数,参数指定查询条件,不指定条件则查询全部记录。

8、删除记录

> db.storeCollection.remove({'version':'0.1'}) WriteResult({ "nRemoved" : 2 })> db.storeCollection.findOne() null
  1. 创建索引
> use pagedbswitched to db pagedb> db.page.ensureIndex({'title':1, 'url':-1}) {    "createdCollectionAutomatically" : true,    "numIndexesBefore" : 1,    "numIndexesAfter" : 2,    "ok" : 1}> db.system.indexes.find() { "v" : 1, "key" : { "_id" : 1 }, "name" : "_id_", "ns" : "pagedb.page" }{ "v" : 1, "key" : { "title" : 1, "url" : -1 }, "name" : "title_1_url_-1", "ns" : "pagedb.page" }
  1. 查询索引
> db.page.getIndexes() [    {        "v" : 1,        "key" : {            "_id" : 1        },        "name" : "_id_",        "ns" : "pagedb.page"    },    {        "v" : 1,        "key" : {            "title" : 1,            "url" : -1        },        "name" : "title_1_url_-1",        "ns" : "pagedb.page"    }]
  1. 删除索引
> db.mycoll.dropIndex(name)2018-01-02T23:45:50.155+0000 E QUERY    ReferenceError: name is not defined    at (shell):1:21> db.mycoll.dropIndexes() { "ok" : 0, "errmsg" : "ns not found" }>
  1. 索引重建
> db.page.reIndex() {    "nIndexesWas" : 2,    "nIndexes" : 2,    "indexes" : [        {            "key" : {                "_id" : 1            },            "name" : "_id_",            "ns" : "pagedb.page"        },        {            "key" : {                "title" : 1,                "url" : -1            },            "name" : "title_1_url_-1",            "ns" : "pagedb.page"        }    ],    "ok" : 1}
  1. 统计集合记录数
> use fragmentswitched to db fragment> db.baseSe.count()36749
  1. 查询并统计结果记录数
> use fragmentswitched to db fragment> db.baseSe.find().count()36749
  1. 查询指定数据库的集合当前可用的存储空间
> use fragmentswitched to db fragment> db.baseSe.storageSize()142564096
  1. 查询指定数据库的集合分配的存储空间
> db.baseSe.totalSize()144096000

2.4 启动与终止

1. 正常启动[root@BenLam-vm_0 ~]# mongod --dbpath /database --logfile /var/mongo.log说明:指定数据存储目录和日志目录如果采用安全认证模式,需要加上--auth选项,如:[root@BenLam-vm_0 ~]# mongod --auth --dbpath /database --logfile /var/mongo.log2. 以修复模式启动[root@BenLam-vm_0 ~]# mongod --repair以修复模式启动数据库。实际很可能数据库数据损坏或数据状态不一致,导致无法正常启动MongoDB服务器,根据启动信息可以看到需要进行修复。或者执行:[root@BenLam-vm_0 ~]# mongod -f /etc/mongodb.conf --repair3. 终止服务器进程> db.shutdownServer()终止数据库服务器进程。或者,可以直接kill掉mongod进程即可。[root@BenLam-vm_0 ~]# kill your_mongod_services

2.5 备份、恢复与迁移管理

1. 备份全部数据库[root@BenLam-vm_0 ~]# mkdir testbak[root@BenLam-vm_0 ~]# cd testbak[root@BenLam-vm_0 ~]# mongodump说明:默认备份目录及数据文件格式为./dump/[databasename]/[collectionname].bson2. 备份指定数据库[root@BenLam-vm_0 ~]# mongodump -d pagedb说明:备份数据库pagedb中的数据。3. 备份一个数据库中的某个集合[root@BenLam-vm_0 ~]# mongodump -d pagedb -c page说明:备份数据库pagedb的page集合。4. 恢复全部数据库[root@BenLam-vm_0 ~]# cd testbak[root@BenLam-vm_0 ~]# mongorestore --drop说明:将备份的所有数据库恢复到数据库,--drop指定恢复数据之前删除原来数据库数据,否则会造成回复后的数据中数据重复。5. 恢复某个数据库的数据[root@BenLam-vm_0 ~]# cd testbak[root@BenLam-vm_0 ~]# mongorestore -d pagedb --drop说明:将备份的pagedb的数据恢复到数据库。6. 恢复某个数据库的某个集合的数据[root@BenLam-vm_0 ~]# cd testbak[root@BenLam-vm_0 ~]# mongorestore -d pagedb -c page --drop说明:将备份的pagedb的的page集合的数据恢复到数据库。

3. Redis

Redis 教程:直达链接

3.1 Redis启动

本地启动:redis-cli远程启动:redis-cli -h host -p port -a password

3.2 Redis连接

  1. 验证密码是否正确
AUTH password
  1. 打印字符串
ECHO message
  1. 查看服务是否运行
PING
  1. 关闭当前连接
QUIT
  1. 切换到指定的数据库
SELECT index

3.3 Redis keys命令

  1. 序列化给定的key并返回序列化的值
DEL keyDUMP key
  1. 检查给定的key是否存在
EXISTS key
  1. 为key设置过期时间
EXPIRE key seconds
  1. 用时间戳的方式给key设置过期时间
EXPIRE key timestamp
  1. 设置key的过期时间以毫秒计
PEXPIRE key milliseconds
  1. 查找所有符合给定模式的key
KEYS pattern
  1. 将当前数据库的key移动到数据库db当中
MOVE key db
  1. 移除key的过期时间,key将持久保存
PERSIST key
  1. 以毫秒为单位返回key的剩余过期时间
PTTL key
  1. 以秒为单位,返回给定key的剩余生存时间
TTL key
  1. 从当前数据库中随机返回一个key
RANDOMKEY
  1. 修改key的名称
RENAME key newkey
  1. 仅当newkey不存在时,将key改名为newkey
RENAMENX key newkey
  1. 返回key所存储的值的类型
TYPE key

3.4 Reids字符串命令

  1. SET key value

  2. GET key

  3. GETRANGE key start end

    返回key中字符串值的子字符

  4. GETSET key value

    将给定key的值设为value,并返回key的旧值

  5. GETBIT KEY OFFSET

    对key所储存的字符串值,获取指定偏移量上的位

  6. MGET KEY1 KEY2

    获取一个或者多个给定key的值

  7. SETBIT KEY OFFSET VALUE

    对key所是存储的字符串值,设置或清除指定偏移量上的位

  8. SETEX key seconds value

    将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。

  9. SETNX key value

    只有在 key 不存在时设置 key 的值。

  10. SETRANGE key offset value

    用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。

  11. STRLEN key

    返回 key 所储存的字符串值的长度。

  12. MSET key value [key value ...]

    同时设置一个或多个 key-value 对。

  13. MSETNX key value [key value ...]

    同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。

  14. PSETEX key milliseconds value

    这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。

  15. INCR key

    将 key 中储存的数字值增一。

  16. INCRBY key increment

    将 key 所储存的值加上给定的增量值(increment)。

  17. INCRBYFLOAT key increment

    将 key 所储存的值加上给定的浮点增量值(increment)。

  18. DECR key

    将 key 中储存的数字值减一。

  19. DECRBY key decrement

    key 所储存的值减去给定的减量值(decrement)。

  20. APPEND key value

    如果 key 已经存在并且是一个字符串, APPEND 命令将 指定value 追加到改 key 原来的值(value)的末尾。

 

转载于:https://www.cnblogs.com/BenLam/p/10407055.html

你可能感兴趣的文章
新手android环境搭建、debug调试及各种插件安装__图文全解
查看>>
未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0”提供程序 win2008R2 X64 IIS7.5
查看>>
Diffuse贴图+Lightmap+Ambient
查看>>
矩阵树定理
查看>>
[算法]Evaluate Reverse Polish Notation
查看>>
go语言之进阶篇接口的定义和实现以及接口的继承
查看>>
SmartPhone手机网站的制作
查看>>
自适应全屏与居中算法
查看>>
构建之法阅读笔记(一)
查看>>
帮助你设计的50个自由和新鲜的图标集
查看>>
Glusterfs[转]
查看>>
javascript缩写
查看>>
GA来源分析
查看>>
常用统计指标
查看>>
iOS设置圆角矩形和阴影效果
查看>>
在博客园的第一篇文章,先简单自述一下吧
查看>>
深入了解 Dojo 的服务器推送技术
查看>>
hdu 4284 状态压缩
查看>>
逆向分析技术
查看>>
Latex
查看>>