• Spring boot配置MongoDB以及Morphia踩坑记录


    pom

    因为项目中采用Morphia(MongoDBODM框架,对象-文档映射(object-document mapper)),因此需要在pom文件中引入相应依赖:

            <dependency>
                <groupId>dev.morphia.morphia</groupId>
                <artifactId>core</artifactId>
                <version>1.5.3</version>
            </dependency>
    

    因为Morphia依赖于mongo-java-driver,因此无需在pom文件中继续导入mongo-java-driver.

    配置

    (1) 配置文件

    application.yaml中配置如下所示:

      data:
        mongodb:
          database: {数据库名称}
          uri: mongodb://{用户名}:{密码}@{服务器地址}:27017/{数据库名称}
    

    上述配置中,{}包围的地方请按照各自项目实际情况填写.

    (2) 代码配置

    @Data
    @Configuration
    public class MorphiaConfig {
    
        private MongoClient mongoClient;
    
        /**
         * 设置连接最大空闲时间(到达时间,连接关闭)
         * @return mongo client属性
         */
        @Bean
        public MongoClientOptions mongoClientOptions() {
            return MongoClientOptions.builder()
                    .maxConnectionIdleTime(6000 * 5)
                    .maxConnectionLifeTime(0)
                    .build();
        }
    
        @Autowired
        public MorphiaConfig(MongoClient mongoClient) {
            this.mongoClient = mongoClient;
        }
    
        @Bean
        public Datastore datastore(@Autowired MongoClient mongoClient) {
            Morphia res = new Morphia();
            // 确定Mongo实体类的存放包名
            res.mapPackage("com.test.log.entity");
            Datastore datastore = res.createDatastore(mongoClient, "ops");
            //  为实体类创建索引
            datastore.ensureIndexes();
            return datastore;
        }
    }
    

    代码中无需自行配置MongoClient(Spring boot会自动完成MongoClient的初始化),当然也允许自行设置Mongo的连接参数.

    实体类

    项目中需要存放日志,并且通过MongoDBTTL特性设置过期时间,以便通过MongoDB完成日志删除任务.

    @Builder
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    // 必须添加,以便Morphia识别此类为`MongoDB`的实体类,`logInfo`是表名
    @Entity(value = "logInfo", noClassnameStored = true)
    @Indexes({
            // expireTime存放日志过期时间,创建TTL index
            @Index(fields = @Field(value = "expireTime"), options = @IndexOptions(expireAfterSeconds = 0)),
            // 创建复合索引
            @Index(fields = {@Field("deviceId"), @Field("module"), @Field(value = "time", type = DESC)}),
            @Index(fields = {@Field("deviceId"), @Field(value = "time", type = DESC)})
    })
    public class LogInfo {
        @Id
        private ObjectId id;
        private Date time;
        @JsonIgnore
        private Date expireTime;
        private String module;
        private String level;
        private String deviceId;
        private String msg;
    }
    

    日志的存放和读取是在不同的项目完成,在查询MongoDB时遇到反序列化问题,异常如下所示:

    WARN  dev.morphia.mapping.DefaultCreator - Class not found defined in dbObj:
    

    查询源码分析,是因为Morphia在存储数据的时候,会将实体类名称存入数据库中.
    查询时Morphia根据类名查找相应的实体类并进行反序列化.
    因为不同的项目中,实体类的包名不一致导致出现以上错误.
    解决方案比较简单,通过注解告知Morphia存储数据时不要存储包名即可,具体如下所示:

    `@Entity(value = "logInfo", noClassnameStored = true)`.
    

    CRUD操作

    (1) 存储操作

        LogInfo logInfo = LogInfo.builder()
                .time(dateTime)
                .expireTime(dateExpireTime)
                .level(level)
                .module(module)
                .deviceId(deviceId)
                .msg(msg)
                .build();
                try {
            //插入日志到mongoDB
            datastore.save(logInfo);
        } catch (RuntimeException e) {
            log.error(AppStatus.IDB_WRITE_FAIL.getError(), e);
        }
    

    (2) 查询操作

        final Query<LogInfo> query = datastore.createQuery(LogInfo.class).filter("deviceId = ",     request.getDeviceId());
        // 列表查询
        if (!CollectionUtils.isEmpty(request.getModules())) {
            query.filter("module in ", request.getModules().toArray());
        }
        // 根据时间查询,使用filter就不太恰当了
        if (null != request.getStartTime()) {
            query.field("time").greaterThanOrEq(request.getStartTime());
        }
        if (null != request.getFinishTime()) {
            query.field("time").lessThanOrEq(request.getFinishTime());
        }
    
        // 查询记录总数
        int count = query.count());
    
        // 设置排序规则,查询具体数据
        query.order(Sort.descending("time"));
        // 获取数据游标
        MongoCursor<LogInfo> logInfoMongoCursor = query.find(
                new FindOptions()
                    .skip((request.getPageNum() - 1) * request.getPageSize())
                    .limit(request.getPageSize())
            );
        // 通过数据游标,逐个获取数据记录
        while (logInfoMongoCursor.hasNext()) {
            logInfoPage.add(logInfoMongoCursor.next());
        }
    

    删除以及更新操作就不再赘述,Morphia接口比较明晰,容易入门.

    PS:
    如果您觉得我的文章对您有帮助,请关注我的微信公众号,谢谢!
    程序员打怪之路

  • 相关阅读:
    结对第一次—疫情统计可视化(原型设计)
    软工实践寒假作业(2/2)
    test
    软工实践寒假作业(1/2)
    json的基本用法
    个人作业——软件工程实践总结&个人技术博客
    个人作业——软件评测
    结对第二次作业——某次疫情统计可视化的实现
    寒假作业(2/2)— 疫情统计
    软工实践寒假作业(1/2)
  • 原文地址:https://www.cnblogs.com/jason1990/p/11065800.html
Copyright © 2020-2023  润新知