Java EE--组件篇 Mongodb

目录

前言

Mongodb

下载安装

初识Mongodb

SpringBoot集成Mongodb

insert和save的区别?

delete系列方法的注意点

QBE查询时的细节问题


前言

带着问题学java系列博文之java基础篇。从问题出发,学习java知识。


Mongodb

来自百度百科——MongoDB是一个基于分布式文件存储的数据库,由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

 

下载安装

linux下安装mongodb:https://blog.csdn.net/qq_41107231/article/details/108028319

安装可视化工具:NoSqlBooster(免费)  或者 Studio3T(收费)

 

初识Mongodb

概念对比:以mysql为例,类比其中的概念

mysql

mongodb

解释

database

database

数据库

table

collection

数据表

row

document

数据表行记录/文档

column

field

数据字段/域

index

index

索引

primary key

primary key

主键,mongodb自动在集合中添加_id主键

table joins

 

表连接,mongodb不支持表连接

 

SpringBoot集成Mongodb

1.引入依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-mongodb</artifactId>
        </dependency>

2.起步配置

spring:
  data:
    mongodb:
      ##uri的字串解释 mongodb://用户名:密码@ip:端口(/账号对应的数据库(可以不添加))
      uri: mongodb://zst:xxx@localhost:27017
      database: mydb
    ##这里使用host、port、username、password分别配置的方式无法连接,必须使用uri的方式
    ##问题原因:创建账号的时候,是在admin数据库下创建的,该账号的权限是admin数据库,但是要操作的数据却在mydb数据库中,因此存在冲突
    ##解决办法:修改对应用户的对应数据库为mydb即可(自己尝试并没有解决问题)。
    ##查看用户账号的方法:使用root用户连接mongodb,查看admin数据库下的system.user表

#配置日志中打印执行语句
#logging.level.org.springframework.data.mongodb.core=DEBUG
logging:
  level:
    org:
      springframework:
        data:
          mongodb:
            core: debug

3.实体类实现

import org.springframework.data.mongodb.core.mapping.Document;

@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
@Document( collection = "student")
public class Student {
    @Id
    private String id;

    private String name;
    private int age;
    private String address;
}

实体类使用mongodb的注解Document,表示它是一个文档类。(类似于jpa的注解@Table,表示是对应一个数据库表的类)

4.Repository实现

@Repository
public interface StudentRepository extends MongoRepository<Student,String> {}

前面讲过hibernate、spring-data-jpa,当时使用的就是repository,这里也是一样。因为我们导入的依赖是spring-boot-starter-data-mongo,很明显是spring官方封装的mongodb启动器。它的使用也和hibernate中的repository类似。

5.使用repository实现增删改查

@SpringBootTest
@RunWith(SpringRunner.class)
public class StudentRepositoryTest {

    //使用repository实现CRUD操作
    @Autowired
    private StudentRepository repository;

    // insert 和 save 的区别
    @Test
    public void testAdd(){
        Student student = new Student();
        student.setName("Android程序员");
        student.setAge(7);
        student.setAddress("安徽合肥高新彩虹路幼儿园");
        repository.insert(student);
        //mongodb自动生成主键id,并保存
        System.out.println(student);

        student.setAge(5);
        repository.save(student);
        System.out.println(student);
    }

    //注意delete(entity)并不是条件删除,和deleteById其实是一样的,都是根据id删除
    //deleteAll(list<entity>)也并不是条件删除,也是遍历根据id删除
    @Test
    public void testDelete(){
        repository.deleteById("5fdc16099cf60746d0b8278d");
        repository.deleteAll();
    }


    @Test
    public void testQuery(){
        // 简单查询
        repository.findById("5fdc16099cf60746d0b8278d");
        repository.findAll();
        // QBE
        // 设置条件
        ExampleMatcher matcher = ExampleMatcher.matching()
                // address字段包含参数值
                .withMatcher("address",ExampleMatcher.GenericPropertyMatchers.contains())
                // name字段以参数值结尾
                .withMatcher("name",ExampleMatcher.GenericPropertyMatchers.endsWith())
                // age 不作为条件(注意由于age是int型,默认值是0,不是null,所以查询时会被作为条件之一)
                .withIgnorePaths("age")
                // 忽略null属性(默认忽略,可以不添加)
                .withIgnoreNullValues();
        // 设置条件值
        Student student = new Student();
        student.setAddress("幼儿园");
        student.setName("程序员");
        // 排序
        Sort sort = Sort.by(Sort.Order.desc("age"));
        // 执行条件查询(地址包含“幼儿园”,名字以“程序员”结尾,查询结果按照年龄倒序排列)
        List<Student> students = repository.findAll(Example.of(student, matcher),sort);
        for (Student student1 : students) {
            System.out.println(student1);
        }
        
        // repository不支持QBC
        
        //分页查询
        Page<Student> studentPage = repository.findAll(PageRequest.of(0, 3));
        System.out.println("totalCount"+studentPage.getTotalElements()+";totalPage"+studentPage.getTotalPages());
        for (Student student1 : studentPage.getContent()) {
            System.out.println(student1);
        }

        // 直接在repository中定义属性方法查询
        List<Student> studentList = repository.findStudentByNameIsContainingAndAddressEndingWith("程序员", "幼儿园");
        for (Student student1 : studentList) {
            System.out.println(student1);
        }
    }
}

insert和save的区别?

insert强调新增,如果插入数据的主键id重复则会报错;

save较为通用,当保存数据的主键id为空时,则等同于insert新增;当主键id重复时,则执行更新操作,相当于根据主键id更新对应数据;repository不具备update方法。

delete系列方法的注意点

和spring-data-jpa的repository一样,delete系列方法,虽然有delete(entity)和deleteAll(list<entity>),但是要注意它并不是条件删除,而是根据主键id删除。如果传入的实例没有设置主键,则删除方法会报错。

QBE查询时的细节问题

spring-data-mongo封装的repository支持QBE,不支持QBC(spring-data-jpa封装的specificationexecutor支持QBC)。如上例,再进行QBE查询时,需要注意几个细节问题:

1.基础类型的属性不要忽视,即使没有在传参的实例中进行值设定,但是由于基础类型都有默认值(比如 int型默认为0),此时repository.findAll(example)时,也会把它作为条件之一,且是相等匹配。所以不要忘记添加上忽略该属性:

// age 不作为条件(注意由于age是int型,默认值是0,不是null,所以查询时会被作为条件之一)
.withIgnorePaths("age")

2.其他属性值没有赋值,默认是null,repository查询时会默认去除,不作为条件,为了保险,建议也加上这句:

// 忽略null属性(默认忽略,可以不添加)
.withIgnoreNullValues();

6.使用spring封装的mongoTemplate实现复杂查询(分组、聚合,复杂条件查询)

如上,使用repository可以实现基本的条件查询,也支持QBE,进行一定的复杂条件查询,但是当遇到分组、聚合查询时,或者遇到既要条件查询、又要分页、还要排序时,repository就显得有点不够用了。这个时候就需要用到spring封装的mongoTemplate,它支持分组、聚合查询,也支持使用QBC进行更加复杂的条件查询(灵活组合更多)。

@SpringBootTest
@RunWith(SpringRunner.class)
public class StudentRepositoryTest {
    //使用spring封装的mongoTemplate实现CRUD操作,可以实现复杂查询:聚合、分组、多表查询等,因此推荐使用template
    @Resource
    private MongoTemplate mongoTemplate;

    @Test
    public void testTemplate(){
        // insert 和 save与repository是一样的
        Student student = new Student();
        student.setName("hack");
        student.setAddress("合肥瑶海");
        student.setAge(27);
        mongoTemplate.insert(student);

        student.setAge(28);
        mongoTemplate.save(student);


        // remove(entity) 和 repository的delete(entity)是一样的,实例的其他属性值不作为条件,仅根据主键id删除
        Student student1 = new Student();
        student1.setId("5fdc1aa49cf6074668f55418");
        student1.setAddress("安徽合肥高新彩虹路幼儿园");
        student1.setName("李刚");
        mongoTemplate.remove(student1);

        //条件查询:QBC
        Query query = new Query();
        Criteria criteria = new Criteria();
        query.addCriteria(criteria.where("age").gte(4).lt(7));
        query.addCriteria(criteria.where("address").regex("合肥"));
        //查询4<=age<7且address包含"合肥"的所有结果
        List<Student> students = mongoTemplate.find(query, Student.class);
        for (Student stu : students) {
            System.out.println(stu.toString());
        }
        System.out.println("-----------------华丽的分割线-------------------");

        Pageable pageable = PageRequest.of(0,3);
        query.with(pageable);
        query.with(Sort.by(Sort.Order.desc("age")));
        //根据age倒序排序,并且分页查询
        List<Student> list = mongoTemplate.find(query, Student.class);
        for (Student stu : list) {
            System.out.println(stu);
        }
    }

    @Test
    public void testAggregation(){
        //分组聚合:注意分组的字段直接作为新数据集的实体类主键,所以这里NameGroup中用id来接收name,不能为其他属性名,否则为空值。
        AggregationResults<NameGroup> aggregate = mongoTemplate.aggregate(Aggregation.newAggregation(
                Aggregation.group("name").count().as("count"))
                , Student.class, NameGroup.class);
        Iterator<NameGroup> iterator = aggregate.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next().toString());
        }
        System.out.println("-----------------华丽的分割线-------------------");
        //使用Aggregation预设各种条件查询和分组规则
        Aggregation aggregation = Aggregation.newAggregation(Aggregation.match(new Criteria().where("age").gte(4).lt(28))
                ,Aggregation.group("name").count().as("count"));
        AggregationResults<NameGroup> nameGroups = mongoTemplate.aggregate(aggregation, Student.class, NameGroup.class);
        Iterator<NameGroup> groupIterator = nameGroups.iterator();
        while (groupIterator.hasNext()){
            System.out.println(groupIterator.next().toString());
        }
    }
}

***:注意使用主键id接收分组的属性,这里不能写成其他,必须是id。


以上系个人理解,如果存在错误,欢迎大家指正。原创不易,转载请注明出处!

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值