Spring Boot整合MongoDB

因为疫情的原因加上自己个人私事也比较多,有好一段时间没有写东西了,趁着这周有时间准备学习点新的东西。公司的项目已经在开发当中了,接口写了不少但是都还没有测过。过年及年后那段时间一直在鼓捣Docker和k8s,自己也写了一点文档,因为比较凌乱,所以暂时就没有发布出来,后期有时间在弄吧。今天想了想也不知道写点什么,思来想去,感觉看看mogondb吧,mongodb也是自己很久之前都想了解和学习的,记得那时候mongodb版本才刚开始支持ACID。好了,闲话少说,开始吧!

一、安装

mongodb从官方地址直接根据系统下载,我是linux系统,下载之后解压。并将可执行文件添加到PATH:

## 添加mogodb到PATH
export PATH=<mongodb-install-directory>/bin:$PATH

根据需要创建数据存储路径

mkdir -p /home/ypcfly/ypcfly/software/MongoDB/mongodb/data

另外创建自定义了配置文件:mongodb.conf

port=27017

dbpath=/home/ypcfly/ypcfly/software/MongoDB/mongodb/data

logpath=/home/ypcfly/ypcfly/software/MongoDB/mongodb/logs/mongodb.log

pidfilepath=/home/ypcfly/ypcfly/software/MongoDB/mongodb/mongo.pid

fork=true

logappend=true

#auth=true

之后进入到bin目录下,启动mongodb并指定加载的配置文件

./mongod --config /home/ypcfly/ypcfly/software/MongoDB/mongodb/mongodb.conf

接着在bin目录下执行命令,进入到控制台

./mongo

mongodb的命令也不复杂,就是写起来没有SQL那么顺手,常用的命令也就那些,这里不做过多的介绍。首先创建一个用户并创建一个database。
切换到admin数据库

use admin  ##然后创建一个管理员
switched to db admin
## 创建管理员
db.createUser({user:"root",pwd:"123456",roles:[roles:"root"]
db.auth('root','123456')
## 创建一个数据库和数据库用户
use mongon_db
switched to db mongon_db
##创建mongo_db的管理员
db.createUser({user:"ypcfly",pwd:"123456",roles:[{role:"dbOwner",db:"mongo_db"}]})
##创建一个user表
db.createCollection("user")

mongondb的用法我觉得还是要在使用的过程中去学,而不是单独的为学而学。以上完成之后我们通过spring boot来使用一下mongodb。

二、spring boot整合mongodb

创建一个spring boot项目,引入mongodb的依赖:spring-boot-starter-data-mongodb。
另外说一点就是idea的database工具目前是支持mongodb的,所以我直接通过database工具连接mongodb。
项目引入mongodb的依赖之后需要在项目中进行配置:

server.port=11000

spring.application.name=mongodb-test
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=mongo_db
spring.data.mongodb.username=ypcfly
spring.data.mongodb.password=123456
## 使用URI
#spring.data.mongodb.uri=mongodb://localhost:27017/mongo_db

配置中可以使用uri的方式加上用户名和密码,或者就是host加端口号加数据库名称,这个就看个人的喜好了。之后启动项目,一切正常。
接下来就要对mongodb做一些CRUD了,按照传统的关系型数据库一个表一般都会对应着一个或多个java的实体类。所以我们先创建一个简单的实体类-User以便对数据库进行操作,代码如下:

@Data
@Document(value = "user")
public class User {

    private String id;

    private String userName;

    private Integer age;

    private String sex;

    private String address;

    private String mobile;
}

@Document注解的值就是表示这个类对应着mongodb中的一个Collection,用传统关系型数据库来对比就是Table。就像spring-data-jpa中的@Entity注解一样。创建好数据模型之后,接下来就是对数据库进行CRUD。如果对spring比较熟悉的话都应该知道spring data对数据库的操作一般都提供了两种方式,一种是模板,比如JDBCTemplateElasticsearchTemplate甚至RedisTemplate,另外一种就是Repository,比如ElasticsearchRepository等等。同样mongodb也为我们提供了这两种方式,接下来我们通过小的demo简单的了解一下。

三、demo演示

在第一步中我们创建好user表(collection)之后里面还没有任何的数据,我们先创建好相应的Controller、Service,这里就不再贴代码了。
创建UserRepository

public interface UserRepository extends MongoRepository<User, String> {
}

在Service的实现类当中我们需要注入MongoTemplateUserRepository。这里说个题外话,最近在使用idea的过程当中采用属性注入bean会有提示说:Field injection is not recommended ,即不推荐使用属性方式注入,自己也网上看了下,确实目前一般推荐使用构造注入或set方法注入的方式,自己这个习惯还是跟着改一下。创建Service的实现类,代码如下:

@Slf4j
@Service
public class MongoDBServiceImpl implements MongoDBService {

    private static final Gson GSON = new Gson();

    private MongoTemplate mongoTemplate;

    private UserRepository userRepository;

    @Autowired
    public void setMongoTemplate(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    @Override
    public User insert(User user) {

        User result = mongoTemplate.insert(user,"user");
//        User result = userRepository.insert(user);
        log.info(">>>> result={} <<<<",GSON.toJson(result));
        return result;
    }

    @Override
    public User update(User user) {
        User result = mongoTemplate.save(user);
//        User result = userRepository.save(user);
        log.info(">>>> result={} <<<<",GSON.toJson(result));
        return result;
    }

    @Override
    public List<User> query(User user) {
        ExampleMatcher matcher = ExampleMatcher.matching()
                .withMatcher("age",ExampleMatcher.GenericPropertyMatchers.exact())
                .withMatcher("userName",ExampleMatcher.GenericPropertyMatchers.exact())
                .withMatcher("address",ExampleMatcher.GenericPropertyMatchers.contains());
        Example<User> example = Example.of(user,matcher);
        List<User> userList = userRepository.findAll(example, Sort.by(Sort.Order.desc("age")));

        userList = mongoTemplate.find(Query.query(Criteria.byExample(user)).with(Sort.by(Sort.Order.asc("age"))),User.class);
        return userList;
    }

    @Override
    public Boolean delete(String id) {
        // 根据id删除
        userRepository.deleteById(id);
        DeleteResult deleteResult = mongoTemplate.remove(Query.query(Criteria.where("id").is(id)),User.class);
        log.info(">>>> delete count={} <<<<",deleteResult.getDeletedCount());
        return Boolean.TRUE;
    }

根据上面的代码不难发现不管是MongoTemplateMongoRepository提供的基本的功能都比较接近,MongoTemplate提供的方法更多且更偏向于底层;MongoRepository封装的更好一些。就简单的操作来看个人感觉使用MongoRepository更好一些。
通过使用http调用一下我们的CRUD接口发现都没有问题,这里就不贴相关代码了。这里说一下mongodb的主键问题,mongodb使用的主键是ObjectId,它通过时间戳+机器标识+进程ID+自增计数器生成的,在上面的User实体类中我并没有在id属性上加@Id注解,但是这并不影响mongodb中id的生成。这点和使用spring-data-jpa还是有点区别的。
最后说一个自己踩的坑,在条件查询的时候我在调用接口时传入的参数字符串都是"",导致在查询的时候查询不出数据,当时自己很奇怪,是不是自己哪里的姿势不正确,后来debug才意识到,如果根据""是查询不出数据的,因为之前都是将用户传入的DTO转成Entity的,所以传入""一般不影响后面使用Entity进行查询,但是今天我是直接用Entity接受参数并查询的,导致数据查询出问题。
通过上面的demo我发现使用了MongoRepository好像语法也没那么重要了,mongodb怎么进行查询?不知道,反正有MongoRepository,简单的功能使用起来真的挺简单,但是我语法还是要去学习一下的,另外mongodb一些重要特性比如索引、ACID等等,后期有时间在看。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343