Spring整合组件_MongoDB


MongoDB简介

MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。

特点:高性能、易部署、易使用,存储数据非常方便。

主要功能特性:

? 面向集合存储,易存储对象类型的数据

? 模式自由

? 支持动态查询

? 支持完全索引,包含内部对象

? 支持复制和故障恢复

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

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

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

不足:MongoDB作为一个非关系型数据库有其局限性。MongoDB不支持事务操作,所以需要用到事务的应用建议不用MongoDB,另外MongoDB目前不支持join操作,需要复杂查询的应用也不建议使用MongoDB。

mongodb是属于内存还是硬盘存储?

mongodb的数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,这样提高查询效率,即所谓的内存数据映射,所以mongodb本身很吃内存。不过MongoDB3.0版本以后会好很多。

快速入门

pom配置


<dependency>
    <groupId>org.mongodbgroupId>
    <artifactId>mongo-java-driverartifactId>
    <version>3.12.1version>
dependency>

<dependency>
    <groupId>org.springframework.datagroupId>
    <artifactId>spring-data-mongodbartifactId>
    <version>2.0.2.RELEASEversion>
dependency>


<dependency>
    <groupId>com.github.jsqlparsergroupId>
    <artifactId>jsqlparserartifactId>
    <version>4.0version>
dependency>

<dependency>
    <groupId>com.github.pagehelpergroupId>
    <artifactId>pagehelperartifactId>
    <version>5.2.0version>
dependency>

配置MongoDB

import com.mongodb.MongoClient;
import com.mongodb.MongoCredential;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.mongodb.core.MongoClientFactoryBean;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;

@EnableMongoRepositories
@ComponentScan(basePackages = "com.spring.mongodb.repository") //指定@Repository注解的包
@Configuration
public class MongoDBConfig {

    /**
     * 创建MongoClient
     *
     * @return
     * @throws Exception
     */
    @Bean
    public MongoClientFactoryBean mongoClient() throws Exception {
        MongoClientFactoryBean mongoClientFactoryBean = new MongoClientFactoryBean();
        mongoClientFactoryBean.setHost("127.0.0.1");
        mongoClientFactoryBean.setPort(27017);
        MongoCredential credential = MongoCredential.createCredential("root", "test", "root".toCharArray());
        mongoClientFactoryBean.setCredentials(new MongoCredential[]{credential});
        return mongoClientFactoryBean;
    }

    /**
     * 配置MongoTemplate基于模板的访问
     *
     * @param mongoClient
     * @return
     */
    @Bean
    public MongoTemplate mongoTemplate(MongoClient mongoClient) {
        return new MongoTemplate(mongoClient, "test");
    }
}

基础操作类 MongodbDao

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;

import com.github.pagehelper.PageInfo;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;

/**
 * mongodb 基础操作类
 *
 * @param 
 * @author linhongwei
 */
@Repository
public class MongodbDaoextends IdEntity> {

    private static final Logger logger = LoggerFactory.getLogger(MongodbDao.class);

    private static final int DEFAULT_SKIP = 0;
    private static final int DEFAULT_LIMIT = 200;
    private Class entityClass;

    @Autowired
    protected MongoTemplate mongoTemplate;

    public MongodbDao() {
        //通过反射机制获取泛型的类类型
        Type type = this.getClass().getGenericSuperclass(); // generic 泛型
        if(type instanceof ParameterizedType){
            // 强制转化“参数化类型”
            ParameterizedType parameterizedType = (ParameterizedType) type;
            // 参数化类型中可能有多个泛型参数
            Type[] types = parameterizedType.getActualTypeArguments();
            // 获取数据的第一个元素(User.class)
            entityClass = (Class) types[0]; // com.oa.shore.entity.User.class
        }
    }

    // ======= 增 ============
    public void save(T t) {
        mongoTemplate.save(t);
        logger.debug("save entity: {}", t);
    }

    public void insertAll(List list) {
        mongoTemplate.insertAll(list);
    }

    // ======= 删 ============

    /**
     * 删除对象
     *
     * @param t
     */
    public void delete(T t) {
        mongoTemplate.remove(t);
    }

    /**
     * 根据id 删除对象
     *
     * @param id
     */
    public void deleteById(String id) {
        Criteria criteria = Criteria.where("id").is(id);
        Query query = new Query(criteria);
        mongoTemplate.remove(query, entityClass);
    }

    /**
     * 根据条件删除
     */
    public void delete(Query query) {
        mongoTemplate.remove(query, entityClass);
    }

    /**
     * 删除该collection 的所有的数据
     */
    public void deleteAll() {
        mongoTemplate.dropCollection(entityClass);
    }

    // ======= 改 ============
    public void update(Query query, Update update) {
        mongoTemplate.findAndModify(query, update, entityClass);
    }

    // ======= 查 ============
    public List findAll() {
        return mongoTemplate.findAll(entityClass);
    }

    /**
     * 根据查询query 查找list
     *
     * @param query
     * @return
     */
    public List find(Query query) {
        return mongoTemplate.find(query, entityClass);
    }

    /**
     * 按照字段排序 - 顺序  
* *
@param query 查询条件
*
@param properties 排序字段
*
@return */ public List findWithOrderAsc(Query query, String... properties) { Sort sort = new Sort(Direction.ASC, properties); query.with(sort); return mongoTemplate.find(query, entityClass); } /** * 按照字段排序 - 逆序
* *
@param query 查询条件
*
@param properties 排序字段
*
@return */ public List findWithOrderDesc(Query query, String... properties) { Sort sort = new Sort(Direction.DESC, properties); query.with(sort); return mongoTemplate.find(query, entityClass); } /** * 根据查询query 查找一个对象 * * @param query * @return */ public T findOne(Query query) { return mongoTemplate.findOne(query, entityClass); } /** * 根据 id 查询对象 * * @param id * @return */ public T findById(String id) { return mongoTemplate.findById(id, entityClass); } /** * 根据id 和 集合名字查询对象 * * @param id * @param collectionName * @return */ public T findById(String id, String collectionName) { return mongoTemplate.findById(id, entityClass, collectionName); } /** * 查询分页 tips:[不要skip 太多的页数,如果跳过太多会严重影响效率。最大不要skip 20000页] * * @param page * @param query * @return */ public PageInfo findPage(PageInfo page, Query query) { long count = this.count(query); page.setTotal(count); int pageNumber = page.getPageNum(); int pageSize = page.getPageSize(); query.skip((pageNumber - 1) * pageSize).limit(pageSize); List list = this.find(query); page.setList(list); return page; } public long count(Query query) { return mongoTemplate.count(query, entityClass); } /** * 获取collection的名字,默认是dao范型T的名字
* 例如: StudentScoreDao extends MongodbDao <StudentScore>
* 则返回的名字是:StudentScore * *
@return */ private String getCollectionName() { return entityClass.getSimpleName(); } }

基础实体类 IdEntity

import java.io.Serializable;

/**
 * 实体基础类,所有的实体都继承该类
 * @author linhongwei
 */
public class IdEntity implements Serializable {
    private static final long serialVersionUID = -8279493522154678891L;
    private String id;

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

}

测试

1、实体类 StudentScore

import java.io.Serializable;
import java.util.List;
 
/**
 * 测试实体类
 * @author linhongwei
 */
public class StudentScore extends IdEntity implements Serializable {

    private static final long serialVersionUID = 1126745404897398026L;
    /**
     * 学生姓名
     */
    private String username;
 
 
    /**
     * 学生成绩
     */
    private List scoreList;
 
    public String getUsername() {
        return username;
    }
 
    public void setUsername(String username) {
        this.username = username;
    }
 
    public List getScoreList() {
        return scoreList;
    }
 
    public void setScoreList(List scoreList) {
        this.scoreList = scoreList;
    }

    @Override
    public String toString() {
        return "StudentScore{" +
                "username='" + username + '\'' +
                ", scoreList=" + scoreList +
                '}';
    }
}

2、实体类的dao操作类 StudentScoreDao

import com.spring.mongodb.MongodbDao;
import com.spring.mongodb.document.StudentScore;
import org.springframework.stereotype.Repository;

/**
 * 继承MongodbDao
* 此类对StudentScore对增删改查和分页方法都已经有了
*
@author linhongwei */ @Repository public class StudentScoreDao extends MongodbDao { }

3、测试验证

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={RootConfig.class, WebConfig.class}) //如果是Java Config配置的,指定相关的配置类
@WebAppConfiguration
public class MongoDbTest {

    @Autowired
    private StudentScoreDao studentScoreDao;

    @Test
    public void test(){
        StudentScore studentScore = new StudentScore();
        studentScore.setUsername("hello");
        studentScore.setId("1234567");
        studentScore.setScoreList(Arrays.asList(95d, 97d, 78d));
        studentScoreDao.save(studentScore);

        StudentScore info = studentScoreDao.findById("1234567");
        System.out.println(info.toString());
    }
}

MongoTemplate API

常用的方法:

  • mongoTemplate.findAll(Student.class): 查询Student文档的全部数据
  • mongoTemplate.findById(, Student.class): 查询Student文档id为id的数据
  • mongoTemplate.find(query, Student.class);: 根据query内的查询条件查询
  • mongoTemplate.upsert(query, update, Student.class): 修改
  • mongoTemplate.remove(query, Student.class): 删除
  • mongoTemplate.insert(student): 新增

Query对象:

(1) 创建一个query对象(用来封装所有条件对象),再创建一个criteria对象(用来构建条件)

(2) 精准条件:criteria.and(“key”).is(“条件”) ;模糊条件:criteria.and(“key”).regex(“条件”)

(3) 封装条件:query.addCriteria(criteria)

(4) 大于(创建新的criteria):Criteria gt = Criteria.where(“key”).gt(“条件”)

小于(创建新的criteria):Criteria lt = Criteria.where(“key”).lt(“条件”)

(5) Query.addCriteria(new Criteria().andOperator(gt,lt));

(6) 一个query中只能有一个andOperator()。其参数也可以是Criteria数组。

(7) 排序 :query.with(new Sort(Sort.Direction.ASC, "age"). and(new Sort(Sort.Direction.DESC, "date")))