说起数据库我们最容易想到的就是 Oracle 、MySql、Sql Server 等等。这些声名远扬的数据库都属于传统的关系型数据库。每一款数据库都有着自己特点,但是呢所有的关系型数据库都满足国际SQL标准。所有的关系型数据库都有着共同的优点。比如:事务的一致性;符合标准的二维表格格式。我们从小学开始就开始接触使用表格进行数据统计。所以关系型数据库非常容易理解和学习。关系型数据库呢已经在很长一段时间里统治了软件行业的数据存储的市场。
与之相悖的呢,就是目前市面上绝大多数的编程语言都是面向对象的。比如Java、Python、C++等等。这就导致了从编程语言到数据存储之间存在在一条理念上的鸿沟。想要跨过这条鸿沟,各种语言分别推出了自己的解决方案。拿Java来说,从JDK 底层的JDBC ,再到各种各样的ORM 框架,比如Hibernate、Mybatis、Spring JDBC等等。但是要通过这样的解决方案来实现数据库的数据存储就需要开发者们去额外学习和掌握这些技能。从一定的角度来说就是增大了开发者的学习成本。于是乎NoSql(非关系型)数据库就应运而生。最有名的NoSql数据库我想应该是Redis,但是Redis的应用场景大多是在高可用和高并发场景下。因为Redis是将数据保存在内存中的,虽然Redis也支持数据持久化,但是有过了解的小伙伴应该都知道Redis的数据持久化并不和传统意义上的数据库相同,它更适用于解决突发的系统Down机而保持数据不会大量丢失的问题。那么今天呢我就来简单说说另一个NoSql数据库,MongoDB。
“MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似 json 的 bjson 格式,因此可以存储比较复杂的数据类型。MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。” 以上是我引用网上对MongoDB的介绍。简单来说就是“面向集合,格式自由(bjson),文档型数据库”。可以理解为数据以集合的形式存储、数据格式是BJSON(JSON的拓展、支持更加复杂的数据类型)。接下来我就来揭开Mongodb的面纱。
(这里省略的MongoDB的安装过程,因为基本都是傻瓜式安装。。。)
MongoDB概念解析
SQL 术语/概念 mongodb术语/概念 解释/说明
database database 数据库
table collection 数据库表/集合
row document 数据库记录行/文档
column field 数据字段/域
index index 索引
table joins ~~~ 表连接,MongoDB不支持
primary key primary key 主键,MongoDB自动将_id字段设置为主键
例子
在关系型数据库中
userinfo 表
id | username | age | |
1 | 张三 | zhangsan@qq.com | 20 |
2 | 李四 | lisi@abc.com | 24 |
userInfo集合
{
"_id" : ObjectId("89779879798"),
"username" : "张三",
"email" : "zhangsan@abc.com",
"age" : 20
}
{
"_id" : ObjectId("151515151515151"),
"username" : "李四",
"age" : 25
}
几个简单的数据库命令
在bin目录中双击mongo.exe就可以运行自带的客户端进行交互了 ,也可以在命令行通过如下方式方式启动。(这里我将mongodb的安装目录放在环境变量中,并将Mongdb建立为一个windows服务了)
1.显示所有的数据库
show dbs
2. 切换/创建数据库
use + database name
3. 插入数据
db.集合名.insert({
})
4.查询数据
db.find()
5.更新数据
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
....
这里只介绍了简单操作的命令,大多数情况下我们都是在图形界面工具下操作MongoDB的。 这里分享一下我用的工具Robo 3T
Java 操作MongoDB
获取所有的集合名称
public class MongoDB01 {
public static void main(String[] args) {
// 创建连接
MongoClient client = new MongoClient("localhost", 27017);
// 连接数据库
MongoDatabase localdb = client.getDatabase("localdb");
// 得到所有集合的名称
MongoIterable<String> colsIte = localdb.listCollectionNames();
MongoCursor<String> it = colsIte.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
System.out.println("================================");
for (String colName : localdb.listCollectionNames()) {
System.out.println(colName);
}
client.close();
}
}
新增数据
public static void main(String[] args) {
MongoClient mongoClient = new MongoClient("localhost", 27017);
MongoDatabase localdb = mongoClient.getDatabase("localdb");
// localdb.createCollection("mycol2");
MongoCollection<Document> mycol2 = localdb.getCollection("mycol2");
System.out.println(mycol2.countDocuments());
Document document = new Document();
document.append("username", "张三").append("age", 18);
mycol2.insertOne(document);
System.out.println(mycol2.countDocuments(new BasicDBObject("username", "张三")));
mongoClient.close();
}
public class FindDocument {
public static void main(String[] args) {
MongoClient mongoClient = new MongoClient("127.0.0.1", 27017);
MongoDatabase localdb = mongoClient.getDatabase("localdb");
MongoCollection<Document> mycol1 = localdb.getCollection("mycol1");
// 查找所有document
FindIterable<Document> documents = mycol1.find();
for (Document document : documents) {
System.out.println(document);
}
System.out.println("--------------------------------");
//查找name = 张三的document
FindIterable<Document> documents1 = mycol1.find(new BasicDBObject("name", "张三"));
for (Document document : documents1) {
System.out.println(document);
}
}
}
相比于JDBC 是不是简单很多?只需要简单几行代码,要知道原生的JDBC 操作数据库可是需要一大堆代码的。
Spring 整合MongoDB
首先引入相关的jar包,Spring 官方提供了Spring Data用于与各种数据库交互,我这里也使用了Spring Data。
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-commons</artifactId>
<version>2.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.1.10.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.11.0</version>
</dependency>
applicationContext-mongodb.xml 配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/data/mongo https://www.springframework.org/schema/data/mongo/spring-mongo.xsd">
<mongo:mongo-client host="127.0.0.1" port="27017" id="mongo"></mongo:mongo-client>
<bean class="org.springframework.data.mongodb.core.MongoTemplate">
<constructor-arg ref="mongo"></constructor-arg>
<constructor-arg name="databaseName" value="localdb"></constructor-arg>
</bean>
</beans>
Spring data 提供了MongoTemplate ,这个对象封装了MongoDB的一切操作。感兴趣的小伙伴可以看看源码。
几个简单的测试demo:
创建实体类User
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "mycol1")
@EqualsAndHashCode
public class User {
@Id
String id;
String name;
int age;
String sex;
Date birthhday;
}
@RunWith(value = SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/applicationContext-*.xml"})
public class MongoDBTestor {
@Autowired
private MongoTemplate mongoTemplate;
@Test
public void test1() {
MongoDatabase db = mongoTemplate.getDb();
System.err.println(db.getName());
MongoIterable<String> mongoNames = db.listCollectionNames();
MongoCursor<String> iterator = mongoNames.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
@Test
public void test2() {
List<User> users = mongoTemplate.findAll(User.class);
users.forEach(System.out::println);
List<User> userList = mongoTemplate.find(new Query(Criteria.where("name").is("suben")), User.class);
userList.forEach(System.out::println);
}
@Test
public void test3() {
ExecutableRemoveOperation.ExecutableRemove<User> remove = mongoTemplate.remove(User.class);
DeleteResult all = remove.all();
System.out.println(all.getDeletedCount());
}
@Test
public void test4() {
// User user = new User();
// user.setAge(19);
// user.setName("张三");
// user.setSex("男");
// user.setRole(new Role("sdfsf","管理员","N"));
// user = mongoTemplate.insert(user);
// System.out.println(user);
//
User user = mongoTemplate.findById("5d7a6a82cabab751a36fe196", User.class);
System.out.println(user);
}
}
Spring Boot与MongoDB 整合
现在正赶上Spring Boot大热的时候,一个搞Java开发的如果不会Spring Boot 就好像没学过Java一样。自然我们也少不了和Spring Boot 进行整合。
引入需要的Spring Boot starter
<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-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
application.yml配置
server:
port: 8080
spring:
mvc:
date-format: yyyy-MM-dd
http:
encoding:
charset: UTF-8
jackson:
time-zone: GMT+8
date-format: yyyy-MM-dd
data:
mongodb:
database: localdb
host: localhost
port: 27017
同样的也需要创建一个实体类User
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(collection = "mycol1")
@EqualsAndHashCode
public class User {
@Id
String id;
String name;
int age;
String sex;
Date birthhday;
}
测试demo:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpbmongodbApplicationTests {
@Autowired
MongoTemplate mongoTemplate;
@Test
public void test1() {
MongoDatabase db = mongoTemplate.getDb();
MongoCollection<Document> mycol1 = db.getCollection("mycol1");
FindIterable<Document> documents = mycol1.find();
MongoCursor<Document> iterator = documents.iterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
@Test
public void test2() {
List<User> users = mongoTemplate.find(new Query(Criteria.where("name").is("苏犇")), User.class);
for (User user : users) {
System.out.println(user);
}
}
@Test
public void test3() {
User user = new User();
user.setAge(12);
user.setBirthhday(new Date());
user.setName("李四");
user.setSex("男");
user = mongoTemplate.insert(user);
System.out.println(user);
}
}
本来到这里也就可以结束了,但是我突然有个想法,不知道 Spring Data + MongoDB 对JDK 8 中的一些特性支持怎么样。于是我在实体类中创建了一个LocalDate 类型的属性date ,如下
再来测试一下数据测试插入:
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpbmongodbApplicationTests {
@Autowired
MongoTemplate mongoTemplate;
.............
@Test
public void test4() {
User user = new User();
user.setAge(15);
user.setBirthhday(new Date());
user.setName("李四1");
user.setSex("女");
user.setDate(LocalDate.now());
user = mongoTemplate.insert(user);
System.out.println(user);
}
}
程序运行成功,并且mongo db 的id 也自动给回填上了。
查一下数据库
可以看到刚才那条数据也正常插入mongodb了。并且可以看到无论是java.util.Date 还是 java.time.LocalDate 都会被已mongoDB的Date数据类型存入DB 。可以看到Spring Data + MongoDB 对JDK 8中的新特性LocalDate 支持还是非常好的。