一、什么是NoSQL?
NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
NoSQL的优点/缺点:
优点:高可扩展性、分布式计算、低成本、架构的灵活性,半结构化数据、没有复杂的关系
缺点:没有标准化、有限的查询功能(到目前为止)、最终一致是不直观的程序
NoSQL数据库分类:
类型 | 部分代表 | 特点 |
列存储 |
Hbase Cassandra Hypertable |
顾名思义,是按列存储数据的。最大的特点是方便存储结构化和半结构化数据,方便做数据压缩,对针对某一列或者某几列的查询有非常大的IO优势。 |
文档存储 |
MongoDB CouchDB |
文档存储一般用类似json的格式存储,存储的内容是文档型的。这样也就有机会对某些字段建立索引,实现关系数据库的某些功能。 |
key-value存储 |
MemcacheDB Redis |
可以通过key快速查询到其value。一般来说,存储不管value的格式,照单全收。(Redis包含了其他功能) |
图存储 |
Neo4J FlockDB |
图形关系的最佳存储。使用传统关系数据库来解决的话性能低下,而且设计使用不方便。 |
对象存储 |
db4o Versant |
通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据 |
xml数据库 |
Berkeley DB XML BaseX |
高效的存储XML数据,并支持XML的内部查询语法,比如XQuery,Xpath |
二、什么是MongoDB?
菜鸟教程:https://www.runoob.com/mongodb/mongodb-tutorial.html
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。
MongoDB 将数据存储为一个文档,数据结构由键值(key-value)键值对组成。MongoDB文档类似于JSON对象。字段值可以包含其他文档,数组及文档数组。
1、MongoDB概念/与SQL区别
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
示例:
2、MongoDB连接
mongodb://[username:password@]host1[:port1] [,host2[:port2],...[,hostN[:portN]]][/[database][?options]]
mongodb:// 这是固定的格式,必须要指定。
username:password@ 可选项,如果设置,在连接数据库服务器之后,驱动都会尝试登录这个数据库
host1 必须的指定至少一个host, host1 是这个URI唯一要填写的。它指定了要连接服务器的地址。如果要连接复制集,请指定多个主机地址。
portX 可选的指定端口,如果不填,默认为27017
/database 如果指定username:password@,连接并验证登录指定数据库。若不指定,默认打开 test 数据库。
?options 是连接选项。如果不使用/database,则前面需要加上/。所有连接选项都是键值对name=value,键值对之间通过&或;(分号)隔开
如:
使用用户名fred,密码foobar登录localhost的baz数据库:mongodb://fred:foobar@localhost/baz
连接 replica set 三台服务器 (端口 27017, 27018, 和27019):mongodb://localhost,localhost:27018,localhost:27019
3、常用的命令:
1、show dbs :显示所有数据库的列表
2、use [db名称]:指定一个数据库、如果没有则会创建此数据库
3、db:显示当前数据库对象或集合
4、show collections:显示当前库下所有的集合
5、db.dropshiyongDatabase():先使用use命令切换到要删除的库下,然后使用此命令删除当前库
6、db.collection.drop():删除集合
7、db.createCollection(name, options):创建集合,options可选参数(具体参考文档)。
注意: 在 MongoDB 中,集合只有在内容插入后才会创建! 就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
8、db.COLLECTION_NAME.insert(document) :向集合中插入文档(一条记录),如果集合mycol2不存在,会自动创建
9、db.col.remove({'key1':'MongoDB 教程'}):删除
4、MongoDB查询文档
db.collection.find(query, projection)
query :可选,使用查询操作符指定查询条件
projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)
db.col.find().pretty(): 使用pretty方法,使结果易读
1)MongoDB与RDBMS WHERE语句比较
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key>:<value> } |
db.col.find({"key1":"value1"}).pretty() |
where key1 = 'value1' |
小于 | {<key>:{$lt:<value>}} |
db.col.find({"key1":{$lt:50}}).pretty() |
where key1 < 50 |
小于或等于 | {<key>:{$lte:<value>}} |
db.col.find({"key1":{$lte:50}}).pretty() |
where key1 <= 50 |
大于 | {<key>:{$gt:<value>}} |
db.col.find({"key1":{$gt:50}}).pretty() |
where key1 > 50 |
大于或等于 | {<key>:{$gte:<value>}} |
db.col.find({"key1":{$gte:50}}).pretty() |
where key1 >= 50 |
不等于 | {<key>:{$ne:<value>}} |
db.col.find({"key1":{$ne:50}}).pretty() |
where key1 != 50 |
2)AND 条件
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件。语法格式如下:
>db.col.find({key1:value1, key2:value2}).pretty()
3)OR 条件
OR 条件语句使用了关键字 $or,语法格式如下:
>db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
表示查询键为key1,值为value1或键为key2,值为value2的文档
4)AND 和 OR 联合使用
>db.col.find({"likes": {$gt:50}, $or: [{"by": "菜鸟教程"},{"title": "MongoDB 教程"}]}).pretty()
5)排序 ,使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。
>db.COLLECTION_NAME.find().sort({KEY:1})
5、索引
索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构
1) 创建索引:createIndex()
注意在 3.0.0 版本前创建索引方法为 db.collection.ensureIndex(),之后的版本使用了 db.collection.createIndex() 方法,ensureIndex() 还能用,但只是 createIndex() 的别名。
>db.collection.createIndex(keys, options)
key为要创建索引的字段,1表示按升序创建索引,-1表示按降序创建索引。如:db.col.createIndex({"title":1,"description":-1}),表示创建title和description两个字段的索引,一个升序,一个降序
options 选项参考文档
6、与Java整合
1)引入依赖
<dependencies> <dependency> <groupId>org.mongodb</groupId> <artifactId>mongo-java-driver</artifactId> <version>3.5.0</version> </dependency> </dependencies>
2)建立连接
MongoClientURI connectionString = new MongoClientURI("mongodb://localhost:27017,localhost:27018,localhost:27019"); // MongoClient实例表示与数据库的连接池。即使有多个线程,您也只需要一个MongoClient类的实例。 // 所以我们可以在给定的数据库集群创建一个MongoClient实例,并在整个应用程序中使用它 MongoClient mongoClient = new MongoClient(connectionString); // 连接具体数据库 MongoDatabase database = mongoClient.getDatabase("mydb");
3)增删改查操作
// 获取某个集合 MongoCollection<Document> collection = database.getCollection("test"); // 创建一条文档(JSON对象字符串) Document doc = new Document("name", "MongoDB") .append("type", "database") .append("count", 1) .append("info", new Document("x", 203).append("y", 102)); // 插入文档 collection.insertOne(doc); // 批量插入 List<Document> documents = new ArrayList<Document>(); collection.insertMany(documents); // 获取集合下文档数量 collection.count() // 查询集合中的第一条文档 Document myDoc = collection.find().first(); // 查询集合中的所有文档 MongoCursor<Document> cursor = collection.find().iterator(); try { while (cursor.hasNext()) { System.out.println(cursor.next().toJson()); } } finally { cursor.close(); } // 使用filter查询符合条件的记录,如查询field为age,值为26的文档记录 Document myDoc = collection.find(eq("age", 26)).first(); // 查询符合条件(50<i<100)的多条文档,并遍历 // now use a range query to get a larger subset Block<Document> printBlock = new Block<Document>() { @Override public void apply(final Document document) { System.out.println(document.toJson()); } }; collection.find(and(gt("i", 50), lte("i", 100))).forEach(printBlock); // 对i字段进行降序 Document myDoc = collection.find(exists("i")).sort(descending("i")).first(); // 查询到的文档排除掉 _id 字段 Document myDoc = collection.find().projection(excludeId()).first(); // 更新符合过滤器的最多一个文档,使用updateOne。如更新i字段等于10的第一条符合记录的文档,并将i更新为110 collection.updateOne(eq("i", 10), new Document("$set", new Document("i", 110))); // 更新符合过滤器的所有文档,使用updateMany。如更新字段i为10的所有所有文档,返回的UpdateResult 包含更新的文档数 UpdateResult updateResult = collection.updateMany(lt("i", 100), new Document("$inc", new Document("i", 100))); // 删除文档 collection.deleteOne(eq("i", 110)); DeleteResult deleteResult = collection.deleteMany(gte("i", 100));
附录:
Mongo连接工具类:
import com.mongodb.MongoClient; import com.mongodb.MongoClientURI; import com.mongodb.client.MongoDatabase; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.support.PropertiesLoaderUtils; import java.io.IOException; import java.util.Properties; /** * @author yangyongjie * @date 2021/1/25 * @desc */ public enum MongoUtil { /** * 定义一个枚举元素,代表此类的一个实例 */ INSTANCE; private static final Logger LOGGER = LoggerFactory.getLogger(MongoUtil.class); private MongoClient mongoClient; /** * 重写枚举类的构造方法,枚举类经编译后会在将其放在静态代码块中,在类加载的初始化阶段被调用 */ private MongoUtil() { Properties properties = null; try { properties = PropertiesLoaderUtils.loadAllProperties("application.properties"); } catch (IOException e) { e.printStackTrace(); } if (properties != null) { MongoClientURI connectionString = new MongoClientURI(properties.getProperty("mongo.url")); // MongoClient实例表示与数据库的连接池。即使有多个线程,您也只需要一个MongoClient类的实例。 // 所以我们可以在给定的数据库集群创建一个MongoClient实例,并在整个应用程序中使用它 this.mongoClient = new MongoClient(connectionString); } } /*private static MongoClient mongoClient; static { Properties properties = new Properties(); try { InputStream is = ClassLoader.getSystemResourceAsStream("application.properties"); properties.load(is); } catch (IOException e) { e.printStackTrace(); } if (properties != null) { MongoClientURI connectionString = new MongoClientURI(properties.getProperty("mongo.url")); // MongoClient实例表示与数据库的连接池。即使有多个线程,您也只需要一个MongoClient类的实例。 // 所以我们可以在给定的数据库集群创建一个MongoClient实例,并在整个应用程序中使用它 mongoClient = new MongoClient(connectionString); } }*/ public MongoDatabase getDB(String dbName) { if (dbName != null && !"".equals(dbName)) { MongoDatabase database = mongoClient.getDatabase(dbName); return database; } return null; } }
用法:MongoUtil.INSTANCE.getMiShopDB("db")
END.