共计 5745 个字符,预计需要花费 15 分钟才能阅读完成。
1. 前言
我们在企业开发中,最常用的都是关系型数据库(oracle、mysql、sqlserver 等),这类基于 jdbc 的数据交互方式,通过在 spring 中整合 mybatis 就能实现,本系列文章《Spring 系列 - 实战篇(4)- 你有多了解 MyBatis》中就有讲解。
但对于非关系型数据库,就是常说 nosql 数据库,是没办法直接用 mybatis 的,因为它们连 sql 都没有,jdbc 的本质就是一种用于执行 sql 语句的 java api。本文就是以 nosql 数据库中的一员,mongodb 为例。讲解 mongodb 数据库的特点,以及如何在 springboot 中实现常用的增删改查。
2.mongo
2.1. 介绍
mongodb 是面向文档的非关系型数据库,放弃关系模型的主要原因就是为了获得更加方便的扩展性,当然优点不仅如此。
丰富的数据模型 :文档的键(对应关系数据库中:表的字段)不会事先定义也不会固定不变,开发灵活。字段值的类型丰富,可以包含其他文档,数组及文档数组,所以用一条记录就可以表示非常复杂的层次关系。
容易扩展 :mongodb 从最初设计的时候就考虑到了扩展的问题。它所采用的面向文档的数据模型使其可以自动在多台服务器之间分割数据。它还可以平衡集群的数据和负载,自动重排文档。
功能丰富 :有很多强大的辅助工具,让 mongodb 的功能更加强大。(1)可以不用再在数据库写存储过程了,允许在服务端执行脚本,可以用 Javascript 编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。(2)大数据应用的支撑也是一大特色,支撑 mapreduce 和其他聚合工具。
对应第一次接触 mongodb 的朋友,我还是先列出 mysql 和 mongodb 数据库的基本概念对比表吧。
| mysql 概念 | mongo 概念 |
| —- | —- |
| table(表)| collection(集合)|
| row(记录行)| document(文档)|
|column(数据字段)|field(域)|
|index(索引)|index(索引)|
|primary key(主键)| 自动将_id 字段设置为主键 |
|table joins(表连接)| 不支持 |
2.2. 安装和使用
上节说到,mongodb 是为分布式扩展而设计的,在搭建 mongo 集群时要考虑很多配置。但是这并非本文要介绍的内容,本文还是主要以 springboot+mongodb 的应用为主。我们就易于容器环境,最简单的启动一个 mongodb 数据库。
docker run --name domain-mongodb -v /u01/mongo/data/db:/data/db -p 27017:27017 -d mongo
按照上面的命令,就启动好了一个 mongodb,对外映射的端口是 27017。
就像我们在用 oracle 数据库,习惯用 sql/plsql developer 客户端;mysql 数据库,习惯用 navicat 客户端;mongodb,我推荐用 robo 3T。robo 3T 是免费的,在下载页面还有个 studio 3T 的软件,那个是商业收费的,当然功能更加丰富。
安装完成并启动后,连接服务器上的 mongodb。就像我们在 mysql 数据库里面,先创建数据库,再创建表一样。我们先创建集合,再创建文档,注意,mongodb 不需要预设表结构,所以只要填文档的名字就行。如下图,创建了 portal 集合下的三个文档,分别是 oauth_client、oauth_config、user。
3.springboot 代码
接下来会以在 springboot 中,实现对用户信息的操作接口为例,讲解如何实现对 mongodb 数据最简单的增删改查。
3.1. 配置
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
<version>2.0.3.RELEASE</version>
</dependency>
application.yml
spring:
data:
mongodb:
uri: mongodb://ip:port/ 集合名
3.2.pojo
先创建一个 pojo 类,UserEO.java, 对应之前 mongodb 里面的创建的 user 文档,这里有几个知识点。
- @Document:通过该注解,绑定 pojo 类和 mongodb 文档的关系。
- @Field:通过该注解,绑定 pojo 类中字段名和 mongodb 文档中域的关系。
- List<UserBookEO> bookList:mongodb 域的值,不仅可以是基础字段,还可以是其他文档,数组及文档数组等。
@Document(collection = "user")
public class UserEO {
private String username;
private String password;
private String name;
/**
* 创建时间
*/
@JsonFormat(pattern="yyyy.MM.dd HH:mm:ss",timezone = "GMT+8")
@Field("creation_date")
private Date creationDate;
/**
* UserBookEO 类:name,price,amount
*/
private List<UserBookEO> bookList;
public String getUsername() {return username;}
public void setUsername(String username) {this.username = username;}
public String getPassword() {return password;}
public void setPassword(String password) {this.password = password;}
public String getName() {return name;}
public void setName(String name) {this.name = name;}
public Date getCreationDate() {return creationDate;}
public void setCreationDate(Date creationDate) {this.creationDate = creationDate;}
public List<UserBookEO> getBookList() {return bookList;}
public void setBookList(List<UserBookEO> bookList) {this.bookList = bookList;}
}
3.3. dao
dao 层的操作主要依赖于 MongoTemplate 的实现,下列代码中已经列出最常用的增删改成以及分页查询,更多的高级用法,可以去官网看 MongoTemplate 的源码实现。
@Component
public class PaasDao {
@Autowired
private MongoTemplate mongoTemplate;
/**
* 分页查询 user
*
* @param key
* @return
*/
public List<UserEO> queryUsers(String key, int page, int pageSize) {Query query = new Query();
Criteria criteriaUsername = Criteria.where("username").regex(key);
Criteria criteriaName = Criteria.where("name").regex(key);
query.addCriteria(new Criteria().orOperator(criteriaUsername, criteriaName));
// 分页
Sort sort=new Sort(Sort.Direction.DESC, "creation_date");
Pageable pageable=PageRequest.of(page-1,pageSize,sort);
query.with(pageable);
return mongoTemplate.find(query, UserEO.class);
}
/**
* 删除 client
*
* @param username
*/
public void deleteUser(String username) {Query query = new Query(Criteria.where("username").is(username));
mongoTemplate.remove(query, UserEO.class);
}
/**
* 新增 client
*
* @param user
*/
public void addUser(UserEO user) {user.setCreationDate(new Date());
mongoTemplate.save(user);
}
/**
* 更新 user
*
* @param user
*/
public void updateUser(UserEO user) {Query query = new Query(Criteria.where("username").is(user.getUsername()));
Update update = new Update().set("password", user.getPassword())
.set("name",user.getName());
mongoTemplate.updateFirst(query, update, UserEO.class);
}
/**
* 查询存在某 username 的数量
*
* @param username
* @return
*/
public long countUsername(String username) {Query query = new Query(Criteria.where("username").is(username));
return mongoTemplate.count(query, UserEO.class);
}
}
3.4. 接口测试
controller 层就没有太多可展示的了,我就简单的拿新增和查询两个接口来做个测试吧。
@RestController
@RequestMapping(value = "/paas")
public class PaasController {
@Autowired
private PaasDao paasDao;
/**
* 用户(user)- 查询用户
*
* @param request
* @return
*/
@RequestMapping(value = "/user/queryUsers", method = RequestMethod.POST)
public Response queryUsers(@RequestBody Map<String, Object> request) {Integer page = (Integer) request.get("page");
Integer pageSize = (Integer) request.get("pageSize");
String key = request.get("key") == null ? "": (String) request.get("key");
List<UserEO> userEOList=paasDao.queryUsers(key,page,pageSize);
long userCount=paasDao.countUsers(key);
PageQueryResult<UserEO> pageQueryResult = new PageQueryResult<>(userCount,userEOList);
return Response.ok().data(pageQueryResult);
}
/**
* 用户(user)- 新增用户
*
* @param userEO
* @return
*/
@RequestMapping(value = "/user/addUser", method = RequestMethod.POST)
public Response addUser(@RequestBody UserEO userEO) {paasDao.addUser(userEO);
return Response.ok();}
通过新增接口,我们分别传入两组数据:
// 第一组数据
{
"username":"kerry",
"password":"kerry",
"name":"吴晨瑞"
}
// 第二组数据
{
"username":"tony",
"password":"tony",
"name":"托尼",
"bookList":[
{
"name":"红楼梦",
"price":20,
"amount":1
},
{
"name":"三个火枪手",
"price":10,
"amount":2
}
]
}
插入成功后,我们通过 robo 3T 查询一下数据库,验证数据确实插入成功。
接下来再调用查询接口,返回结果如下:
{
"code":"ok",
"data":{
"count":2,
"result":[
{
"username":"tony",
"password":"tony",
"name":"托尼",
"creationDate":"2019.11.17 16:29:34",
"bookList":[
{
"name":"红楼梦",
"price":20,
"amount":1
},
{
"name":"三个火枪手",
"price":10,
"amount":2
}
]
},
{
"username":"kerry",
"password":"kerry",
"name":"吴晨瑞",
"creationDate":"2019.10.30 10:53:55"
}
]
},
"requestid":"e80b71d50c9e45e9bffa3bd0b2abf446"
}
OK,在 springboot 框架下,基于 mongodb 的接口开发,看上去并不困难。