Spring集成MongoDB

业务需要,某个功能模块需要从原先的MySQL关系型数据库转换为非关系型的NoSQL数据库MongoDB。
之前的项目使用的是传统的SSH架构(Spring+SpringMVC+Hibernate),不像现在流行的SpringBoot,集成MongoDB还是需要做一些配置才能完成。
配置过程中最需要注意的一点在于相关依赖的版本。

Spring集成MongoDB的依赖包

需要依赖两个包:

mongo-java-driver

这是一个驱动包,封装了MongoDB的一些类型和操作接口,譬如BasicDBObject,BasicDBList,MongoClient等。这个包不是Spring框架下的,而是Java对MongoDB进行操作可以直接使用的一个包;

spring-data-mongodb

这是一个Spring框架下的包,针对MongoDB的操作进行了封装,属于Spring Data的一个子项目,提供了对MongoDB进行CRUD的统一接口,可以通过继承MongoRepository来使用JPA的方式进行操作。另外也可以通过MongoTemplate等接口来进行操作。这是在mongo-java-driver之上的一层封装。

包依赖关系

这里写图片描述
由上图可见,spring-data-mongo依赖于mongo-java-driver,另外还依赖spring-data-commons。

MongoDB相关配置

首先配置一下MongoDB的相关属性,譬如数据库URL以及端口等等。

mongo.host=localhost
mongo.port=27017
mongo.connectionsPerHost=100
mongo.minConnectionsPerHost=10
mongo.threadsAllowedToBlockForConnectionMultiplier=4
mongo.maxWaitTime=5000
mongo.maxConnectionIdleTime=10000
mongo.maxConnectionLifeTime=100000
mongo.connectTimeout=1000
mongo.socketTimeout=1500
mongo.socketKeepAlive=true
mongo.serverSelectionTimeout=30000

这里设置了Mongo的一些相关属性,譬如主机,端口,超时时间等等。
这些属性要在Spring的配置文件中使用,从而进行集成。如果直接使用MongoClient,MongoCollection等接口进行操作,不通过Spring进行集成,则可以直接在代码中指定,无需增加这些properties配置文件。

applicationcontext配置

接着要进行Spring的集成,通过在applicationcontext.xml中进行相关配置。
①首先引入mongo的命名空间

xmlns:mongo="http://www.springframework.org/schema/data/mongo"
xsi:schemaLocation="http://www.springframework.org/schema/data/mongo
    http://www.springframework.org/schema/data/mongo/spring-mongo-1.4.xsd"

②导入mongo的配置文件

<context:property-placeholder location="classpath:/mongodb.properties"/>

③配置mongo及db-factory

<mongo:mongo id="mongo" host="${mongo.host}" port="${mongo.port}">
        <mongo:options
                connections-per-host="${mongo.connectionsPerHost}"
                threads-allowed-to-block-for-connection-multiplier="${mongo.threadsAllowedToBlockForConnectionMultiplier}"
                max-wait-time="${mongo.maxWaitTime}"
                connect-timeout="${mongo.connectTimeout}"
                socket-timeout="${mongo.socketTimeout}"
                socket-keep-alive="${mongo.socketKeepAlive}"
        />
    </mongo:mongo>

    <mongo:db-factory id="mongoDbFactory" dbname="hdindex" mongo-ref="mongo"/>

④引入MongoTemplate这个bean

<bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">
        <constructor-arg name="mongoDbFactory" ref="mongoDbFactory"/>
    </bean>

关于spring-data-mongodb的版本号

在Maven Repository上可以看到该jar包有多个版本,从大版本上来讲,有1.x和2.x版本。
这里写图片描述
再看一下相关的mongo-java-driver的版本,从大版本上来讲,有0.x,1.x,2.x和3.x版本。
这里写图片描述
那这里就要注意了!
出于对新版本的偏爱,在选择版本时,spring-data-mongodb毫不犹豫地选择了2.x的版本,而mongo-java-driver也选择了3.x版本。
这个时候就会发现,spring-data-mongodb在spring集成引入mongo命名空间的时候就出现了不同。2.x的版本引入的命名空间对应的是2.0版本的xsd,而1.x版本引入的命名空间对应的是1.4版本的xsd(根据具体版本不同,可能是1.x)。
而1.x和2.x的xsd文件是不同的,从大的方面上来讲,xsd中定义的element元素就发生了变化。
1.x中对应的mongo元素是mongo,而2.x对应的mongo元素是mongo-client;
1.x中对应的mongo选项子元素是options,而2.x对应的mongo选项子元素是client-options。


由于导入的是2.x版本的jar包,相应的驱动jar包也需要3.x版本以上,否则在启动时回报错。
当新引入的两个jar包匹配成功之后,再启动发现还是会出现“通配符的匹配很全面, 但无法找到元素 ‘mongo:mongo-client’ 的声明”这样不明所以的错误提示。
在思索和查找资料很久后,考虑到可能是spring-data-commons的版本匹配不对,于是把这个jar包的版本也提升了2.0以上。这个时候更神奇的事情发生了。
通过继承JpaRepository接口的一些自定义Repository在调用findOne的时候发生了编译错误。
查看源码发现findOne的参数变成了一个Example泛型,通过具体的实体类进行构造才行。为了暂时能够编译通过,改用findById接口方法,发现该方法的返回值变成了Optional泛型。
这个时候就崩溃了,要改的地方太多了!


这个时候,意识到新的版本发生了接口大变化,提升版本不是一个好的办法。
于是,灵光一现,做出一个决定:降版本!
spring-data-mongodb版本降到1.x,mongo-java-driver的版本也相应降到2.x。
于是applicationcontext中的配置终于成功了。

MongoTemplate操作

接下来,通过代码进行一下测试:

@Document(collection = "project")
public class Project {

    @Id
    private String id;
    private String description;
    private String region;
    private String city;

    // getter和setter省略
}
@Service
public class MProjectServiceImpl implements IMProjectService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Override
    public List<Project> listProjects() {
        return mongoTemplate.findAll(Project.class);
    }

    @Override
    public String addProject(Project project) {
        mongoTemplate.insert(project);
        return ResultBuilder.getResult(true, project.getId(), "").toString();
    }

    @Override
    public String deleteProject(String projectId) {
        Project project = mongoTemplate.findAndRemove(Query.query(Criteria.where("_id").is(projectId)), Project.class);
        if (project == null) {
            return ResultBuilder.getResult(false, "", "工程不存在").toString();
        } else {
            return ResultBuilder.getResult(true, "", "删除成功").toString();
        }
    }

    @Override
    public String updateProjectInfo(String id, String field, String value) {
        Project project = mongoTemplate.findAndModify(Query.query(Criteria.where("_id").is(id)), Update.update(field, value), Project.class);
        if (project == null) {
            return ResultBuilder.getResult(false, "", "工程不存在").toString();
        } else {
            return ResultBuilder.getResult(true, "", "更新成功").toString();
        }
    }

    @Override
    public List<String> getProjectRegions() {
        List<String> regions = new ArrayList<>();
        DBCursor cursor = mongoTemplate.getCollection("project").find(new BasicDBObject(),
                new BasicDBObject("region", 1));
        while (cursor.hasNext()) {
            regions.add(cursor.next().get("region").toString());
        }
        return regions;
    }
}

针对某一Collection下的文档进行CRUD,全部通过MongoTemplate进行操作。
通过PostMan进行接口测试后查看MongoDB中的数据:

{
    "_id" : ObjectId("5a6983c48814bebd2c817874"),
    "_class" : "com.hdzbk.index.mongo.entity.Project",
    "description" : "介休一中",
    "region" : "山西",
    "city" : "介休"
}

增删改查全部可用。

MongoRepository接口

也可以通过Repository接口进行操作,可以通过命名规范进行查询,也可以通过@Query,@DeleteQuery,@CountQuery等注解进行操作。这里不赘言了!

enjoy!

猜你喜欢

转载自blog.csdn.net/achang07/article/details/79165843