本文代码示例参见:
我们使用Spring Data MongoDB可以方便的在Spring boot项目中操作MongoDB
文档地址:https://docs.spring.io/spring-boot/docs/2.1.1.RELEASE/reference/htmlsingle/#boot-features-mongodb
加载包
在pom文件中加入spring-boot-starter-data-mongodb配置
org.springframework.boot spring-boot-starter-data-mongodb
配置参数
# user - 用户名、secret - 密码、mongo1.example.com - 数据库地址、27017- 端口号、teat - 库名 spring.data.mongodb.uri=mongodb://user:secret@mongo1.example.com:27017/test
实体映射
我们可以通过实体类来进行关系映射,从而能够方便的使用对象进行数据操作。
Spring Data MongoDB提供了一些方便的映射注释供我们使用,下面列出官方说明地址以供参考
官方说明文档:https://docs.spring.io/spring-data/mongodb/docs/2.1.3.RELEASE/reference/html/#mapping-usage
-
@Id:用于标记id字段,没有标记此字段的实体也会自动生成id字段,但是我们无法通过实体来获取id。id建议使用ObjectId类型来创建。
-
@Document:用于标记此实体类是mongodb集合映射类。可以使用collection参数指定集合名称。特别需要注意的是如果实体类没有为任何字段创建索引将不会自动创建集合。
-
@Indexed:用于标记为某一字段创建索引。direction参数可以指定排序方向,升或降序。
-
@CompoundIndex:用于创建复合索引。def参数可以定义复合索引的字段及排序方向。
-
@Transient:被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性。
-
@PersistenceConstructor:用于声明构造函数,作用是把从数据库取出的数据实例化为对象。
-
@Field:用于指定某一个字段映射到数据库中的名称。
-
@DBRef:用于指定与其他集合的级联关系,但是需要注意的是并不会自动创建级联集合。
一个简单的例子:
//注释此类将被映射到数据库的一个集合(collection为集合名称)@Document(collection = "ex_entity_test")//创建联合索引@CompoundIndexes({ //联合索引 name 索引名称 、def 索引字段、parameter1升序、parameter3降序 @CompoundIndex(name = "compound_index", def = "{'parameter1': 1, 'parameter3': -1}")})public class EntityTest implements Serializable { //标记id字段 @Id private ObjectId id; //创建单字段索引(默认ASCENDING 升序、DESCENDING 降序) @Indexed(direction = DESCENDING) private Long parameter1; //修改映射到数据库中的名称 @Field("parameter2_") private String parameter2; private Date parameter3; private Integer parameter4; //关联其他集合(不添加此注释时List将会保存具体的实体值,而添加了此注释List保存的是关联集合的id) @DBRef private Listparameter5; //此字段不映射到数据库 @Transient private Integer parameter6; public EntityTest(){ } //声明构造函数,用于实例化查询结果数据 @PersistenceConstructor public EntityTest(Long parameter1, String parameter2, Date parameter3, Integer parameter4, List parameter5) { this.parameter1 = parameter1; this.parameter2 = parameter2; this.parameter3 = parameter3; this.parameter4 = parameter4; this.parameter5 = parameter5; } public ObjectId getId() { return id; } public void setId(ObjectId id) { this.id = id; } ...... public Integer getParameter6() { return parameter6; } public void setParameter6(Integer parameter6) { this.parameter6 = parameter6; }}
上例关联的集合
//注释此类将被映射到数据库的一个集合(collection为集合名称)@Document(collection = "ex_entity_test1")public class EntityTest1 implements Serializable { //标记id字段 @Id private ObjectId id; //如果实体类没有为任何字段创建索引将不会自动创建集合 @Indexed private Long parameter1; public EntityTest1(){ } public EntityTest1(Long parameter1) { this.parameter1 = parameter1; } public ObjectId getId() { return id; } public void setId(ObjectId id) { this.id = id; } public Long getParameter1() { return parameter1; } public void setParameter1(Long parameter1) { this.parameter1 = parameter1; }}
数据操作
当完成一系列的配置与准备工作后,我们就可以使用MongoTemplate来操作数据库了。
MongoTemplate为我们提供了全面的增删改查等操作数据库的方法,详情可查看官方说明文档和API文档
官方说明文档:https://docs.spring.io/spring-data/mongodb/docs/2.1.3.RELEASE/reference/html/#mongo-template
API文档:https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/MongoTemplate.html
一个简单的例子:
@Controllerpublic class MongoController { @Autowired private MongoTemplate mongoTemplate; @GetMapping(value = "/") public String index(){ return "redirect:/find"; } //新增文档 @GetMapping(value = "/insert") public String insert(){ //insert方法并不提供级联类的保存,所以级联类需要先自己先保存 EntityTest1 entityTest1_1 = new EntityTest1(1000L); //执行完insert后对象entityTest1将会获得保存后的id mongoTemplate.insert(entityTest1_1); //再添加一条 EntityTest1 entityTest1_2 = new EntityTest1(1001L); mongoTemplate.insert(entityTest1_2); //创建列表并将保存后的关联对象添加进去 ArrayListentityTest1List = new ArrayList (); entityTest1List.add(entityTest1_1); entityTest1List.add(entityTest1_2); //新增主体对象 EntityTest entityTest = new EntityTest(100L,"test",new Date(),10,entityTest1List); //新增数据的主键已经存在,则会抛DuplicateKeyException异常 mongoTemplate.insert(entityTest); return "redirect:/find"; } //保存文档 //保存与新增的主要区别在于,如果主键已经存在,新增抛出异常,保存修改数据 @GetMapping(value = "/save") public String save(){ //查询最后一条数据并更新 Sort sort = new Sort(Sort.Direction.DESC,"parameter3"); EntityTest entityTest = mongoTemplate.findOne(Query.query(Criteria.where("")).with(sort),EntityTest.class); entityTest.setParameter4(3000); //保存数据的主键已经存在,则会对已经存在的数据修改 mongoTemplate.save(entityTest); return "redirect:/find"; } //删除文档 @GetMapping(value = "/delete") public String delete(){ //查询第一条数据并删除 EntityTest entityTest = mongoTemplate.findOne(Query.query(Criteria.where("")),EntityTest.class); //remove方法不支持级联删除所以要单独删除子数据 List entityTest1List = entityTest.getParameter5(); for(EntityTest1 entityTest1:entityTest1List){ mongoTemplate.remove(entityTest1); } //删除主数据 mongoTemplate.remove(entityTest); return "redirect:/find"; } //更新文档 @GetMapping(value = "/update") public String update(){ //将查询条件符合的全部文档更新 Query query = new Query(); Update update = Update.update("parameter2_","update"); mongoTemplate.updateMulti(query,update,EntityTest.class); return "redirect:/find"; } //查询文档 @GetMapping(value = "/find") public String find(Model model){ //查询小于当前时间的数据,并按时间倒序排列 Sort sort = new Sort(Sort.Direction.DESC,"parameter3"); List findTestList = mongoTemplate.find(Query.query(Criteria.where("parameter3").lt(new Date())).with(sort) ,EntityTest.class); model.addAttribute("findTestList",findTestList); //使用findOne查询如果结果极为多条,则返回排序在最上面的一条 EntityTest findOneTest = mongoTemplate.findOne(Query.query(Criteria.where("parameter3").lt(new Date())).with(sort) ,EntityTest.class); model.addAttribute("findOneTest",findOneTest); //模糊查询 List findTestList1 = mongoTemplate.find(Query.query(Criteria.where("parameter3").lt(new Date()).and("parameter2").regex("es")) ,EntityTest.class); model.addAttribute("findTestList1",findTestList1); //分页查询(每页3行第2页) Pageable pageable = new PageRequest(1,3,sort); List findTestList2 = mongoTemplate.find(Query.query(Criteria.where("parameter3").lt(new Date())).with(pageable) ,EntityTest.class); //共多少条 Long count = mongoTemplate.count(Query.query(Criteria.where("parameter3").lt(new Date())),EntityTest.class); //返回分页对象 Page page = new PageImpl (findTestList2,pageable,count); model.addAttribute("page",page); //分页查询(通过起始行和数量也可以自己实现分页逻辑) List findTestList3 = mongoTemplate.find(Query.query(Criteria.where("parameter3").lt(new Date())).with(sort).skip(3).limit(3) ,EntityTest.class); model.addAttribute("findTestList3",findTestList3); return "/index"; }}
查询
由于查询相对于其他增删改的操作要复杂一些,所以在这里单独说一下查询。还看上面的例子就可以。
首先我们先介绍一下几个和查询有关的类Query、Criteria、Sort、PageRequest、PageImpl
Query
查询对象定义一个查询的所有要素,其中包括筛选条件、排序、起始行、返回条数等内容
API文档:https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/query/Query.html
常用方法介绍:
query(CriteriaDefinition criteriaDefinition) | 静态方法通过注入一个CriteriaDefinition条件对象获得Query查询对象。在简单查询时使用此方法将非常的方便。 例如:mongoTemplate.find(Query.query(Criteria.where("parameter3").lt(new Date()) |
| 添加一个CriteriaDefinition查询条件类到本次查询 |
| 跳过文档的数量,可以与limit配合使用实现分页效果。 |
| 查询返回的文档数量。 |
| 添加一个Sort排序对象 |
| 添加一个Pageable分页对象。Pageable可以注入一个Sort,所以分页和排序可以一起添加。 例如:Pageable pageable = new PageRequest(1,3,sort); |
Criteria
查询条件类,使用此类定义查询时的查询条件相当于SQL的where。
API文档:https://docs.spring.io/spring-data/mongodb/docs/current/api/org/springframework/data/mongodb/core/query/Criteria.html
常用方法介绍:
( key) | 静态方法,用它可以很方便的定义查询条件 例如:mongoTemplate.find(Query.query(Criteria.where("parameter3").lt(new Date()).and("parameter2").regex("es")) |
( key) | 与操作 |
( o) | 大于 |
( o) | 大于等于 |
(... o) | 包含 |
( o) | 等于 |
( o) | 小于 |
( o) | 小于等于 |
() | 非 |
( re) | 正则表达式 |
(... criteria) | 创建与操作 |
(... criteria) | 创建或操作 |
Sort
查询排序类,使用此类可以创建查询排序。
API文档:https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/Sort.html?is-external=true
常用方法介绍:
( direction, ... properties) | 构造方法创建一个排序。direction为排序方向的枚举类型,properties为排序字段数组 |
( sort) | 多个排序条件链接 |
() | 返回升序排列对象 |
() | 返回降序排列对象 |
PageRequest和PageImpl
这两个类都是分页相关的封装类,与其他数据库的使用方法一样。PageRequest分页请求类,PageImpl为页面封装类。
API文档:https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/PageRequest.html
https://docs.spring.io/spring-data/commons/docs/current/api/org/springframework/data/domain/PageImpl.html