Spring5.x集成MongoDB

  1. 引入依赖

    在pom.xml中添加依赖,只需在spring中引入spring-data-mongodb依赖就好,里面会有MongoDB驱动和其他支持依赖

            <!-- spring整合MongoDB -->
            <dependency>
                <groupId>org.springframework.data</groupId>
                <artifactId>spring-data-mongodb</artifactId>
                <version>2.0.6.RELEASE</version>
            </dependency>

    注意版本问题,每个版本对应的spring版本都不一样,本项目的spring版本是5.0.5.RELEASE,所以引入的spring-data-mongodb的版本是2.0.6.RELEASE,和spring版本适配

  2. 编写配置

    在module.properties中添加属性

    #MongoDB配置
    #主机
    mongo.host=localhost
    #端口号
    mongo.port=27017
    #库名称
    mongo.dbname=ksc
    #账号
    mongo.username=zhupeng
    #密码
    mongo.password=zhupeng
    #每个主机允许的连接数,一个线程变为可用的最大阻塞数
    mongo.connectionsPerHost=8
    #线程队列数,它以上面connectionsPerHost值相乘的结果就是线程队列最大值
    mongo.threadsAllowedToBlockForConnectionMultiplier=4
    #连接超时时间(毫秒)
    mongo.connectTimeout=1000
    #最大等待时间
    mongo.maxWaitTime=1500
    #scoket保持活动
    mongo.socketKeepAlive=true
    #scoket超时时间
    mongo.socketTimeout=1500

    此时需要编写spring-mongo.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:mongo="http://www.springframework.org/schema/data/mongo"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/data/mongo
        http://www.springframework.org/schema/data/mongo/spring-mongo-2.0.xsd
        ">s
        <!-- 方式一:  直接IP和端口号连接数据库-->
        <mongo:mongo-client id="mongo" host="${mongo.host}" port="${mongo.port}">
        <!-- 方式二:IP和端口号连接数据库,并使用用户和密码连接,需要在后面一定添加?authMechanism=SCRAM-SHA-1,血泪史      -->
    <!--    <mongo:mongo-client id="mongo" host="${mongo.host}" port="${mongo.port}"-->
    <!--                        credentials="${mongo.username}:${mongo.password}@${mongo.dbname}?authMechanism=SCRAM-SHA-1">-->
            <mongo:client-options
                    connections-per-host="${mongo.connectionsPerHost}"
                    threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
                    connect-timeout="${mongo.connectTimeout}"
                    max-wait-time="${mongo.maxWaitTime}"
                    socket-keep-alive="${mongo.socketKeepAlive}"
                    socket-timeout="${mongo.socketTimeout}"
    ​
            />
        </mongo:mongo-client>
    ​
        <!-- 设置使用的数据库名 MongoRepositoryFactory-->
        <mongo:db-factory id="mongoDbFactory"
                          dbname="${mongo.dbname}"
                          mongo-ref="mongo"
        />
        <!-- mongodb的模板 -->
        <bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
            <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
        </bean>
        <!--    mongo-template-ref="mongoTemplate"  要加,不然MongoRepository用不了,血泪史-->
        <mongo:repositories base-package="com.digiwin.app.ttt.service.mongo.repository"
                            mongo-template-ref="mongoTemplate" repository-impl-postfix="repository"/>
    ​
    </beans>

  3. 编写代码

    我们定义一个doc实体KnowledgeDoc,用于插入的数据

    @Document(collection = "knowledge_data")
    public class KnowledgeDoc<T> extends BaseDoc {
        @Field("code")
        private String code;
        @Field("name")
        private String name;
        @Field("source")
        private String source;
        @Field("tag")
        private List<String> tag;
        @Field("document")
        private String document;
        @Field("status")
        private Boolean status;
        @Field("customize")
        private T customize;
        @Field("description")
        private String description;
        //此处省略setter getter方法
    }

    编写repository仓储类

    /**
    *此处使用 MongoRepository 方式对数据进行简单的增删改查,MongoRepository<Doc实体, 主键类型> 
    */
    public interface KnowledgeRepository extends MongoRepository<KnowledgeDoc,String> {
    ​
    }

    此处整合MongoDB的两种方法:MongoRepository和MongoTemplate,灵活使用,默认需要MongoTemplate就可以了,本人在整合MongoRepository时出现大坑,网上的配置写法都一样,但都是错误的,都是相互copy的吧。

    编写service接口和实现类

    public interface KnowledgeService {
        /**
         * 测试方法,新增数据
         * @return
         */
        Object addData();
    }
    
    /**
     * @Author: zhupeng@digiwin.com
     * @Datetime: 2021/11/2 15:26
     * @Description:
     * @Version: 0.0.0.1
     */
    @Service
    public class KnowledgeServiceImpl implements KnowledgeService {
    ​
        //注入方式一:构造注入MongoRepository
        private KnowledgeRepository repository;
        public KnowledgeServiceImpl(KnowledgeRepository repository) {
            this.repository = repository;
        }
    ​
        //注入方式二:Autowired注入MongoTemplate
        @Autowired
        private MongoTemplate mongoTemplate;
    ​
        /**
         * 测试方法,新增数据
         *
         * @return
         */
        @Override
        public Object addData() {
            KnowledgeDoc<CustomizeDoc> knowledgeDoc = new KnowledgeDoc<CustomizeDoc>();
            SubprojectDoc subprojectDoc = new SubprojectDoc();
            subprojectDoc.setDeliveryConfirmationNo("201810260071");
            subprojectDoc.setProductName("专案管理—专案规格书—WF");
            subprojectDoc.setStage("1");
            subprojectDoc.setStatus(false);
            subprojectDoc.setSubprojectCode("20181026007");
            subprojectDoc.setSubprojectName("20181026007");
            CustomizeDoc customizeDoc = new CustomizeDoc();
            List<SubprojectDoc> subprojectDocs = new ArrayList<>();
            subprojectDocs.add(subprojectDoc);
            customizeDoc.setSubproject(subprojectDocs);
            customizeDoc.setProjectCode("00000001");
            customizeDoc.setProjectName("认购订单");
            customizeDoc.setCustomerCode("0000130503");
            customizeDoc.setCustomerName("太平洋自行车");
            customizeDoc.setOrderNumber("180090912");
            customizeDoc.setServiceCode("02276000");
            knowledgeDoc.setCustomize(customizeDoc);
            knowledgeDoc.setCode("00000001");
            knowledgeDoc.setName("认购订单");
            knowledgeDoc.setDescription("专案管理—专案规格书—WF");
            knowledgeDoc.setSource("CRM");
            knowledgeDoc.setStatus(false);
            knowledgeDoc.setTenantsid(Long.parseLong(ApplicationToken.tenantSid));
            knowledgeDoc.setCreateName("张三");
            knowledgeDoc.setCreateTime(new Date());
            System.out.println(ChangeUtil.beanToString(knowledgeDoc));
            //方式一:使用MongoRepository实现新增数据
            repository.insert(knowledgeDoc);
            //方式二:使用MongoTemplate实现新增数据
            //mongoTemplate.insert(knowledgeDoc);
            return "新增成功";
        }
    }

    调用,此处木有用postman工具调用接口。在项目启动后,自动执行,去调用新增方法,起到postman调用接口的效果

    /**
     *项目启动后,自动执行
     */
    public class LoadServiceImpl implements ILoadService {
        Logger logger = LoggerFactory.getLogger(LoadServiceImpl.class);
    ​
        private KnowledgeService knowledgeService;
    ​
        @Override
        public Object onLoad(Map<String, Object> map) throws Exception {
            Object data = knowledgeService.addData();
            logger.info((String) data);
            return "OK";
        }
    }
     
  4. 测试

    image-20211103154657819

<think>嗯,用户现在问的是Spring Data MongoDB中的ChangeStreamOptions是否能实现与MongoDB原生驱动同样的功能。首先,我需要回忆一下之前用户的问题,他们之前遇到的是无法导入原生的ChangeStreamOptions,而只能用Spring封装的版本。现在他们想知道Spring的版本是否功能相同。 首先,我需要确认Spring的ChangeStreamOptions和原生的类在功能上是否有差异。可能需要查阅两者的文档或源码。记得Spring Data MongoDB通常是对原生驱动的封装,提供更高级的抽象,但有时候可能不会暴露所有底层选项。 原生的ChangeStreamOptions在MongoDB驱动中用于配置Change Stream的选项,比如设置resume token、batchSize、collation等。而Spring的版本可能封装了这些配置,但有没有可能缺少某些参数呢? 另外,用户可能是在使用Spring的Change Stream支持时遇到了限制,想知道是否需要绕过Spring直接使用原生驱动。或者他们可能担心Spring的封装是否不够灵活,无法满足他们的需求。 需要分析Spring的ChangeStreamOptions提供的方法,比如是否有设置resumeAfter、fullDocument等选项。同时,查看Spring的文档是否有说明支持哪些配置。比如,在Spring Data MongoDB的文档中,Change Stream的支持部分是否有详细说明。 可能还需要比较两者的API。例如,原生的ChangeStreamOptions有resumeAfter方法,而Spring的版本是否有对应的resumeAfter方法,或者是否有不同的命名方式。如果有差异,用户可能需要知道如何通过Spring的API达到同样的效果。 另外,用户可能关心的是是否可以通过Spring的配置来实现原生驱动的所有功能,或者是否存在某些高级功能必须直接使用原生驱动的情况。这时候需要明确两者的兼容性和功能覆盖情况。 还要考虑版本问题,因为用户使用的是Spring Boot 2.7.12和MongoDB驱动4.6.1。不同版本的Spring Data可能对Change Stream的支持程度不同,需要确认该版本下Spring的ChangeStreamOptions是否支持用户需要的功能。 最后,可能需要建议用户如何在使用Spring封装的同时,处理需要原生功能的场景,比如通过混合使用Spring和原生API,或者在某些情况下直接访问底层驱动对象。</think>--- ### **结论:可以覆盖大部分功能,但存在差异** `org.springframework.data.mongodb.core.ChangeStreamOptions` 是 Spring Data MongoDB 对原生 `com.mongodb.client.model.changestream.ChangeStreamOptions` 的封装,**核心功能一致**,但 **API 设计和使用场景有区别**。 --- ### **功能对比** | **功能** | **原生驱动 (`com.mongodb`)** | **Spring Data (`org.springframework.data`)** | |-------------------------|-------------------------------------------------------|------------------------------------------------------| | **Resume Token** | `resumeAfter(BsonDocument)` | `resumeToken(BsonDocument)` | | **Batch Size** | `batchSize(int)` | `batchSize(int)` | | **Full Document 模式** | `fullDocument(FullDocument)` | `fullDocumentLookup(FullDocument)` | | **Collation** | `collation(Collation)` | `collation(Collation)` | | **Max Await Time** | `maxAwaitTime(long, TimeUnit)` | `maxAwaitTime(Duration)` | | **自定义聚合管道** | `startAfter(BsonDocument)` / `startAtOperationTime` | 需通过 `Aggregation` 手动构建 | | **与 Spring 集成** | 需要手动处理会话、事务 | 直接支持 Spring 事务管理、Template API | --- ### **关键差异与限制** #### **1. 方法命名和参数设计** Spring Data 对部分方法进行了适配性调整,例如: - **`resumeToken` vs `resumeAfter`**: Spring 的 `resumeToken` 直接接受 `BsonDocument`,而原生驱动的 `resumeAfter` 需传入操作时间点或逻辑标记。 - **时间单位处理**: Spring 使用 `Duration` 统一管理时间参数,避免 `TimeUnit` 的显式传递。 #### **2. 高级功能依赖原生驱动** 以下场景仍需直接使用 MongoDB 原生类: - **自定义聚合管道操作**(如 `$match` 复杂条件): Spring Data 的 `ChangeStreamOptions` 不直接暴露底层管道构建方法,需通过 `Aggregation` 类间接实现。 - **特定驱动版本的新特性**: 例如,MongoDB 5.0+ 的 [Change Stream Pre-/Post-Image 功能](https://www.mongodb.com/docs/manual/changeStreams/)需要原生 `fullDocumentBeforeChange` 配置,而 Spring Data 可能尚未适配。 #### **3. 事务与会话管理** Spring Data 自动集成 Spring 事务管理器,例如: ```java @Transactional public void listenChanges() { ChangeStreamOptions options = ChangeStreamOptions.builder() .filter(Aggregation.newAggregation(/* ... */)) .build(); mongoTemplate.changeStream("collection", options, MyDocument.class) .forEach(event -> { /* 处理逻辑 */ }); } ``` 原生驱动需手动控制会话: ```java try (ClientSession session = client.startSession()) { MongoCollection<Document> coll = database.getCollection("collection"); coll.watch(session, Arrays.asList(/* 管道 */)) .forEach(document -> { /* 处理逻辑 */ }); } ``` --- ### **何时使用 Spring Data 的封装?** | **场景** | **推荐方案** | |------------------------------|-------------------------------| | 简单监听集合变更 | Spring Data `ChangeStreamOptions` | | 需要与 Spring 事务无缝集成 | Spring Data | | 使用 Spring 的 `MongoTemplate` | Spring Data | | 需要快速实现业务逻辑 | Spring Data | --- ### **何时需要回退到原生驱动?** | **场景** | **推荐方案** | |------------------------------|-------------------------------| | 使用 MongoDB 最新特性(如 Pre-Image) | 原生驱动 + 手动集成 | | 复杂聚合管道操作 | 原生驱动 `Bson` 构建 | | 需要直接控制底层会话或游标 | 原生驱动 | --- ### **混合使用示例** 如果需要在 Spring 项目中部分使用原生功能: ```java @Autowired private MongoTemplate mongoTemplate; public void hybridApproach() { // 使用 Spring 的 ChangeStreamOptions 配置基础参数 ChangeStreamOptions options = ChangeStreamOptions.builder() .batchSize(100) .build(); // 获取原生 MongoCollection MongoCollection<Document> nativeCollection = mongoTemplate.getCollection("your_collection"); // 使用原生驱动扩展配置 com.mongodb.client.model.changestream.ChangeStreamOptions nativeOptions = new ChangeStreamOptions() .fullDocument(FullDocument.UPDATE_LOOKUP) .maxAwaitTime(10, TimeUnit.SECONDS); // 混合监听 nativeCollection.watch(nativeOptions) .withOptions(options.toDocument()) // Spring 配置转为 Bson .forEach(document -> { /* 处理逻辑 */ }); } ``` --- ### **版本适配建议** - **Spring Boot 2.7.x + MongoDB 驱动 4.6.x**: Spring Data 的 `ChangeStreamOptions` 已覆盖大部分常用功能,优先使用。 - **需要 MongoDB 5.0+ 特性**: 升级 Spring Boot 到 3.x 或手动引入更高版本的驱动(注意兼容性)。 --- ### **总结** - **Spring Data 的 `ChangeStreamOptions` 能满足 80% 的常见需求**,且与 Spring 生态无缝集成- **需要底层控制或新特性时,可混合使用原生驱动**,但需注意依赖版本和事务一致性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值