乐优商城(四十八)评论微服务(一)

目录

一、MongoDB简介

1.1 评论数据特点分析

1.2 什么是MongonDB

1.3 MongonDB特点

1.4 MongonDB体系结构

1.5 数据类型

二、走进MongoDB

2.1 MongoDB安装与启动

2.2 常用命令

2.2.1 选择和创建数据库

2.2.2 插入与查询文档

2.2.3 修改与删除文档

2.2.4 统计条数

2.2.5 模糊查询

2.2.6 大于 小于 不等于

2.2.7 包含与不包含

2.2.8 条件连接

2.2.9 列值增长

三、操作MongoDB

3.1 mongodb-driver

3.1.1 查询全部记录

3.1.2 条件查询

3.1.3 插入数据

3.2 SpringDataMongoDB


一、MongoDB简介

1.1 评论数据特点分析

评论两项功能存在以下特点:

(1)数据量大

(2)写入操作频繁

(3)价值较低

对于这样的数据,更适合使用MongoDB来实现数据的存储。

1.2 什么是MongonDB

MongoDB 是一个跨平台的,面向文档的数据库,是当前 NoSQL 数据库产品中最热门的一种。它介于关系数据库和非关系数据库之间,是非关系数据库当中功能最丰富,最像关系数据库的产品。它支持的数据结构非常松散,是类似 JSON 的 BSON 格式,因此可以存储比较复杂的数据类型。MongoDB 的官方网站地址是:https://www.mongodb.com/

1.3 MongonDB特点

MongoDB 最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。它是一个面向集合的,模式自由的文档型数据库。具体特点总结如下:(1)面向集合存储,易于存储对象类型的数据

(2)模式自由

(3)支持动态查询

(4)支持完全索引,包含内部对象

(5)支持复制和故障恢复

(6)使用高效的二进制数据存储,包括大型对象(如视频等)

(7)自动处理碎片,以支持云计算层次的扩展性

(8)支持 Python,PHP,Ruby,Java,C,C#,Javascript,Perl 及 C++语言的驱动程序,社区中也提供了对 Erlang 及.NET 等平台的驱动程序

(9) 文件存储格式为 BSON(一种 JSON 的扩展)

1.4 MongonDB体系结构

MongoDB 的逻辑结构是一种层次结构。主要由:文档(document)、集合(collection)、数据库(database)这三部分组成的。逻辑结构是面向用户的,用户使用 MongoDB 开发应用程序使用的就是逻辑结构。
(1)MongoDB 的文档(document),相当于关系数据库中的一行记录。
(2)多个文档组成一个集合(collection),相当于关系数据库的表。
(3)多个集合(collection),逻辑上组织在一起,就是数据库(database)。
(4)一个 MongoDB 实例支持多个数据库(database)。
文档(document)、集合(collection)、数据库(database)的层次结构如下图:

下表是MongoDB与MySQL数据库逻辑结构概念的对比

MongoDBMySQL
数据库(database)数据库(database)
集合(collections)表(table)
文档(document)行(row)

1.5 数据类型

基本数据类型null:用于表示空值或者不存在的字段,{“x”:null}

布尔型:布尔类型有两个值true和false,{“x”:true}

数值:shell默认使用64为浮点型数值。{“x”:3.14}或{“x”:3}。对于整型值,可以使用NumberInt(4字节符号整数)或NumberLong(8字节符号整数),{“x”:NumberInt(“3”)}{“x”:NumberLong(“3”)}

字符串:UTF-8字符串都可以表示为字符串类型的数据,{“x”:“呵呵”}

日期:日期被存储为自新纪元依赖经过的毫秒数,不存储时区,{“x”:new Date()}

正则表达式:查询时,使用正则表达式作为限定条件,语法与JavaScript的正则表达式相同,{“x”:/[abc]/}

数组:数据列表或数据集可以表示为数组,{“x”: [“a“,“b”,”c”]}

内嵌文档:文档可以嵌套其他文档,被嵌套的文档作为值来处理,{“x”:{“y”:3 }}

对象Id:对象id是一个12字节的字符串,是文档的唯一标识,{“x”: objectId() }

二进制数据:二进制数据是一个任意字节的字符串。它不能直接在shell中使用。如果要将非utf-字符保存到数据库中,二进制数据是唯一的方式。

代码:查询和文档中可以包括任何JavaScript代码,{“x”:function(){/…/}}

二、走进MongoDB

2.1 MongoDB安装与启动

查看菜鸟教程:http://www.runoob.com/mongodb/mongodb-tutorial.html

centos 7下安装mongodb

启动:

./mongod --dbpath=/leyou/mongodb/data --logpath=/leyou/mongodb/logs/logs --logappend  --port=27017 --bind_ip=0.0.0.0 --fork

2.2 常用命令

2.2.1 选择和创建数据库

选择和创建数据库的语法格式:

use 数据库名称

如果数据库不存在则自动创建以下语句创建spit数据库

use spit

2.2.2 插入与查询文档

插入文档的语法格式:

db.集合名称.insert(数据);

测试:

db.spit.insert({content:"飘来荡去",userid:"1011",nickname:"飘来荡去",visits:NumberInt(902)})

以上实例中 spit 是集合名,如果该集合不在该数据库中, MongoDB 会自动创建该集合并插入文档。

查询集合的语法格式:

db.集合名称.find

测试:

db.spit.find()

这里会发现每条文档会有一个叫_id的字段,这个相当于原来关系数据库中表的主键,当在插入文档记录时没有指定该字段,MongoDB会自动创建,其类型是ObjectID类型。如果在插入文档记录时指定该字段也可以,其类型可以是ObjectID类型,也
可以是MongoDB支持的任意类型。

输入以下测试语句:

条件查询:

如果想按一定条件来查询,比如想查询userid为1011的记录,怎么办?很简单!只要在find()中添加参数即可,参数也是json格式,如下:

如果只需要返回符合条件的第一条数据,可以使用findOne命令来实现:

如果想返回指定条数的记录,可以在find方法后调用limit来返回结果,例如:

2.2.3 修改与删除文档

修改文档的语法结构:

db.集合名称.update(条件,修改后的数据)

如果想修改_id为1的记录,浏览量为1000,输入以下语句:

db.spit.update({_id:"1"},{visits:NumberInt(1000)})

执行后,会发现,这条文档除了visits字段其它字段都不见了,为了解决这个问题,需要使用修改器$set来实现,命令如下:

db.spit.update({_id:"2"},{$set:{visits:NumberInt(2000)}})

删除文档的语法结构:

db.集合名称.remove(条件)

以下语句可以将数据全部删除,请慎用

db.spit.remove({})

如果删除visits=902的记录,输入以下语句

db.spit.remove({visits:902})

2.2.4 统计条数

统计记录条件使用count()方法。以下语句统计spit集合的记录数:

db.spit.count()

如果按条件统计 ,例如:统计userid为1011的记录条数

db.spit.count({userid:"1011"})

2.2.5 模糊查询

MongoDB的模糊查询是通过正则表达式的方式实现的。格式为:

/模糊查询字符/

例如,要查询评论内容包含“好极了”的所有文档,代码如下:

db.spit.find({content:/好极了/})

如果要查询评论内容中以“优惠”开头的,代码如下:

db.spit.find({content:/^优惠/})

2.2.6 大于 小于 不等于

<, <=, >, >= 这个操作符也是很常用的,格式如下:

db.集合名称.find({ "field" : { $gt: value }}) // 大于: field > value

db.集合名称.find({ "field" : { $lt: value }}) // 小于: field < value

db.集合名称.find({ "field" : { $gte: value }}) // 大于等于: field >= value

db.集合名称.find({ "field" : { $lte: value }}) // 小于等于: field <= value

db.集合名称.find({ "field" : { $ne: value }}) // 不等于: field != value

示例:查询浏览次数大于1000的记录:

db.spit.find({visits:{$gt:1000}})

2.2.7 包含与不包含

包含使用$in操作符。

示例:查询评论集合中userid字段包含1011和1012的文档

db.spit.find({userid:{$in:["1011","1012"]}})

不包含使用$nin操作符。

示例:查询评论集合中userid字段不包含1011和1012的文档

db.spit.find({userid:{$nin:["1011","1012"]}})

2.2.8 条件连接

如果需要查询同时满足两个以上条件,需要使用$and操作符将条件进行关联。(相当于SQL的and)格式为:

$and:[ { },{ },{ }]

示例:查询评论集合中visits大于等于900 并且小于1000的文档

db.spit.find({$and:[ {visits:{$gte:900}} ,{visits:{$lt:1000} }]})

如果两个以上条件之间是或者的关系,我们使用 操作符进行关联,与前面and的使用方式相同。格式为:

$or:[ { },{ },{ }]

示例:查询吐槽集合中userid为1013,或者浏览量小于2000的文档记录

db.spit.find({$or:[ {userid:"1013"} ,{visits:{$lt:2000} }]})

2.2.9 列值增长

如果想实现对某列值在原有值的基础上进行增加或减少,可以使用$inc运算符来实现

db.spit.update({_id:"2"},{$inc:{visits:NumberInt(1)}})

三、操作MongoDB

3.1 mongodb-driver

mongodb-driver是mongo官方推出的java连接mongoDB的驱动包,相当于JDBC驱动。通过一个入门的案例来了解mongodb-driver的基本使用。

3.1.1 查询全部记录

创建新工程mongodb-demo,引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.mongodb.demo</groupId>
    <artifactId>mongodb-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.mongodb</groupId>
            <artifactId>mongodb-driver</artifactId>
            <version>3.8.2</version>
        </dependency>
    </dependencies>
</project>

创建测试类

import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;


/**
 * @Author: 98050
 * @Time: 2018-11-26 10:30
 * @Feature: mongodb测试
 */
public class Test {

    public static void main(String[] args) {
        //1.创建连接
        MongoClient client = new MongoClient("localhost",27017);
        //2.打开数据库
        MongoDatabase database = client.getDatabase("spitdb");
        //3.获取集合
        MongoCollection<Document> spit = database.getCollection("spit");
        //4.查询记录获取文档集合
        FindIterable<Document> documents = spit.find();
        //5.输出
        for (Document document : documents){
            System.out.println("内容:"+document.getString("content"));
            System.out.println("用户ID:"+document.getString("userid"));
            System.out.println("浏览量:"+document.getInteger("visits"));
            System.out.println("---------------------------------------------");
        }
        //6.关闭连接
        client.close();
    }
}

测试结果:

3.1.2 条件查询

BasicDBObject对象:表示一个具体的记录,BasicDBObject实现了DBObject,是keyvalue的数据结构,用起来和HashMap是基本一致的。

查询userid为1013的记录

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

/**
 * @Author: 98050
 * @Time: 2018-11-26 10:48
 * @Feature:
 */
public class Test2 {

    public static void main(String[] args) {
        //1.创建连接
        MongoClient client = new MongoClient("localhost",27017);
        //2.打开数据库
        MongoDatabase database = client.getDatabase("spitdb");
        //3.获取集合
        MongoCollection<Document> spit = database.getCollection("spit");
        //4.构建查询条件
        BasicDBObject basicDBObject = new BasicDBObject("userid","1013");
        //5.查询记录获取文档集合
        FindIterable<Document> documents = spit.find(basicDBObject);
        //6.输出
        for (Document document : documents){
            System.out.println("内容:"+document.getString("content"));
            System.out.println("用户ID:"+document.getString("userid"));
            System.out.println("浏览量:"+document.getInteger("visits"));
            System.out.println("---------------------------------------------");
        }
        //7.关闭连接
        client.close();
    }
}

结果:

查询浏览量大于1000的记录

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

/**
 * @Author: 98050
 * @Time: 2018-11-26 10:50
 * @Feature:
 */
public class Test3 {
    public static void main(String[] args) {
        //1.创建连接
        MongoClient client = new MongoClient("localhost",27017);
        //2.打开数据库
        MongoDatabase database = client.getDatabase("spitdb");
        //3.获取集合
        MongoCollection<Document> spit = database.getCollection("spit");
        //4.构建查询条件
        BasicDBObject basicDBObject = new BasicDBObject("visits",new BasicDBObject("$gt",1000));
        //5.查询记录获取文档集合
        FindIterable<Document> documents = spit.find(basicDBObject);
        //6.输出
        for (Document document : documents){
            System.out.println("内容:"+document.getString("content"));
            System.out.println("用户ID:"+document.getString("userid"));
            System.out.println("浏览量:"+document.getInteger("visits"));
            System.out.println("---------------------------------------------");
        }
        //7.关闭连接
        client.close();
    }
}

结果:

3.1.3 插入数据

import com.mongodb.BasicDBObject;
import com.mongodb.MongoClient;
import com.mongodb.client.FindIterable;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @Author: 98050
 * @Time: 2018-11-26 10:52
 * @Feature:
 */
public class Test4 {
    public static void main(String[] args) {
        //1.创建连接
        MongoClient client = new MongoClient("localhost",27017);
        //2.打开数据库
        MongoDatabase database = client.getDatabase("spitdb");
        //3.获取集合
        MongoCollection<Document> spit = database.getCollection("spit");
        //4.构建数据
        Map<String,Object> map = new HashMap<String, Object>();
        map.put("content","测试");
        map.put("userid","999");
        map.put("visits","9999");
        map.put("publishtime",new Date());
        Document document = new Document(map);
        //5.插入数据
        spit.insertOne(document);
        //6.关闭连接
        client.close();
    }
}

结果:

3.2 SpringDataMongoDB

SpringData家族成员之一,用于操作MongoDb的持久层框架,封装了底层的mongodb-driver。官网主页: https://spring.io/projects/spring-data-mongodb,乐优商城的评论微服务就采用SpringDataMongoDB框架

自己做的乐优商城的XMIND文件,学习分享下。乐优商城 搭建父工程 pom.xml 添加依赖 springCloud mybatis启动器 通用Mapper启动器 mysql驱动 分页助手启动器 FastDFS客户端 其他配置 构建设置 环境设置 EurekaServer注册中心 添加的依赖 启动类 application.yml 创建Zuul网关 依赖 启动类 application.yml 创建商品微服务 ly-item-interface:主要是对外暴露的API接口及相关实体类 ly-item-service:所有业务逻辑及内部使用接口 创建父工程ly-item ly-item-interface ly-item-service 依赖 启动器 application.yml 添加商品微服务的路由规则 通用工具模块Common utils CookieUtils IdWorker JsonUtils NumberUtils 依赖 通用异常处理 测试结构 pojo service @Service web @RestController @RequestMapping @Autowired @PostMapping 引入Common依赖 Common advice 拦截异常、 CommonExceptionHandler ResponseEntity @ControllerAdvice @ExceptionHandler enums 异常的枚举 、ExceptionEnum exception 自定义异常、LyException 接口RuntimeException @Getter @NoArgsConstructor @AllArgsConstructor vo 异常结果处理对象、ExceptionResult @Data 构造方法ExceptionResult ly-item-service CategoryQuery 分类查询 实体类 @Table(name="tb_category") 声明此对象映射到数据库的数据表,通过它可以为实体指定表(talbe) @Data 注解在类上, 为类提供读写属性, 此外还提供了 equals()、hashCode()、toString() 方法 @Id & @GeneratedValue(strategy= GenerationType.IDENTITY) 自动增长,适用于支持自增字段的数据库 mapper Mapper IdListMapper 根据id操作数据库 @RequestMapping("category") Controller @RestController @Controller 处理HTTP请求 @ResponseBody 返回 json 数据 @GetMapping("list") ResponseEntity @ResponseBody可以直接返回Json结果 不仅可以返回json结果,还可以定义返回的HttpHeaders和HttpStatus service @Service 自动注册到Spring容器,不需要再在applicationContext.xml文件定义bean了 @Autowired 它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。 select select * from category c where c.pid = #{pid} CollectionUtils.isnotblank 判断集合是否为空 测试 可以利用url直接查询数据库,能否访问得到数据 报错 启动类 没有扫描到 @MapperScan("com.leyou.item.mapper") ,目录结构关系 访问网页报错 CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. 跨域问题 浏览器对于ajax请求的一种安全限制:一个页面发起的ajax请求,只能是于当前页同域名的路径,这能有效的阻止跨站攻击。因此:跨域问题 是针对ajax的一种限制。 解决跨域问题的方案 CORS 规范化的跨域请求解决方案,安全可靠 什么是cors 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。 原理 简单请求 当浏览器发现发现的ajax请求是简单请求时,会在请求头中携带一个字段:Origin 如果服务器允许跨域,需要在返回的响应头中携带下面信息 Access-Control-Allow-Origin:可接受的域,是一个具体域名或者*,代表任意 Access-Control-Allow-Credentials:是否允许携带cookie,默认情况下,cors不会携带cookie,除非这个值是true 实现非常简单 gateway网关中编写一个配置类 GlobalCorsConfig 添加CORS配置信息 允许的域,不要写*,否则cookie就无法使用了 是否发送Cookie信息 允许的请求方式 允许的头信息 有效时长 添加映射路径,我们拦截一切请求 返回新的CorsFilter 提交方式 GET 用来获取资源,POST 用来新建资源,PUT 用来更新资源,DELETE 用来删除资源 BUG 分类不能打开,当添加后却能打开。 修改一天的BUG 最后发现是实体类里属性大小写的问题引起。 注意 Bule_bird 就必须写成 BlueBird Brand 查询 实体类 PageResult 响应结果 分页结果一般至少需要两个数据 总条数 total 当前页数据 items 有些还需要总页数 总页数 totalPage Controller @RequestParam(value = "page",defaultValue = "1") Integer page GET和POST请求传的参数会自动转换赋值到@RequestParam 所注解的变量上 defaultValue 默认值 required 默认值为true , 当为false时 这个注解可以不传这个参数 null || .size()==0 ResponseEntity(HttpStatus.NOT_FOUND) 返回404没找到 ResponseEntity.ok 返回ok状态 service 开始分页 通用分页拦截器 PageHelper.startPage(page,row); 过滤 Example查询 Example example = new Example(Brand.class); mybatis的逆向工程中会生成实例及实例对应的example,example用于添加条件,相当where后面的部分 xxxExample example = new xxxExample(); Criteria criteria = new Example().createCriteria(); StringUtils.isNotBlank isNotBlank(str) 等价于 str != null && str.length > 0 && str.trim().length > 0 str.trim() 去掉字符串头尾的空格 测试 报错500 com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Unknown column 'idASC' in 'order clause' 错误:(desc ? "DESC" : "ASC"); 正确:(desc ? " DESC" : " ASC"); 字符串空格问题 新增 Controller (Brand brand,@RequestParam("cids") List cids) ResponseEntity 无返回值 new ResponseEntity(HttpStatus.CREATED); 201成功 service @Transactional 自动纳入 Spring 的事务管理 使用默认配置,抛出异常之后,事务会自动回滚,数据不会插入到数据库。 setId(null) insert(brand) 新增中间表 mapper @Insert (#{cid},#{bid}) @Param 表示给参数命名,名称就是括号中的内容 name 命名为aa,然后sql语句....where s_name= #{aa} 中就可以根据aa得到参数值 修改 回显 Controller @PathVariable("bid") 通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中。 select * from tb_category where id in (select category_id from tb_category_brand where brand_id = #{bid}) 测试 报错500 空指针异常 调用Service时候 忘记@Autowired 保存 VO视图对象 @NoArgsConstructor 生成一个无参数的构造方法 @AllArgsConstructor 会生成一个包含所有变量 Controller @PutMapping 添加信息,倾向于用@PostMapping,如果是更新信息,倾向于用@PutMapping。两者差别不是很明显 return ResponseEntity.ok().build(); 无返回值 service 根据id修改 先删除后新增 删除(前端有问题,待完善) spec Group 品牌分类id查询 实体类 @Transient 指定该属性或字段不是永久的。 它用于注释实体类,映射超类或可嵌入类的属性或字段。 @Column(name = "'numeric'") 用来标识实体类中属性与数据表中字段的对应关系 name 定义了被标注字段在数据库表中所对应字段的名称; mapper service Controller 测试 报错500 实体类@table路径写错 新增 Controller @RequestBody 常用其来处理application/json类型 子主题 2 将请求体中的JSON字符串绑定到相应的bean上 修改 Controller @PutMapping service updateByPrimaryKey 删除 Controller @DeleteMapping @PathVariable Param 规格组id查询规格 url:params?gid=14 @GetMapping("params") Controller @RequestParam 新增 @PostMapping("param") @RequestBody ResponseEntity.status(HttpStatus.CREATED).build(); 修改 @RequestBody 删除 @PathVariable 分支主题 3 遇到的问题 pom.xml 文件未下载完整,删掉后重新下载 能存在重复文件,IDEA不能确定文件路径,需要搜索删掉多余的 Param 删除 小问题:数据库删除后页面没有立即显示 Brand 删除(前端有问题,待完善)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值