组件整合之MongoDB
MongoDB简介
MongoDB是一个基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应用提供可扩展的高性能数据存储解决方案。
MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是它支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。
特点:高性能、易部署、易使用,存储数据非常方便。
主要功能特性:
- 面向集合存储,易存储对象类型的数据
- 模式自由
- 支持动态查询
- 支持完全索引,包含内部对象
- 支持复制和故障恢复
- 使用高效的二进制数据存储,包括大型对象(如视频等)
- 自动处理碎片,以支持云计算层次的扩展性
- 文件存储格式为BSON(一种JSON的扩展)
不足:MongoDB作为一个非关系型数据库有其局限性。MongoDB不支持事务操作,所以需要用到事务的应用建议不用MongoDB,另外MongoDB目前不支持join操作,需要复杂查询的应用也不建议使用MongoDB。
mongodb是属于内存还是硬盘存储?
mongodb的数据是存储在硬盘上的,只不过需要经常读取的数据会被加载到内存中,这样提高查询效率,即所谓的内存数据映射,所以mongodb本身很吃内存。不过MongoDB3.0版本以后会好很多。
快速入门
pom配置
<!-- MongoDB驱动-->
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.1</version>
</dependency>
<!--spring-data-mongodb-->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-mongodb</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<!--分页组件-->
<dependency>
<groupId>com.github.jsqlparser</groupId>
<artifactId>jsqlparser</artifactId>
<version>4.0</version>
</dependency>
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper</artifactId>
<version>5.2.0</version>
</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 <T>
* @author linhongwei
*/
@Repository
public class MongodbDao<T extends 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<T> 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<T>) 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<T> 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<T> findAll() {
return mongoTemplate.findAll(entityClass);
}
/**
* 根据查询query 查找list
*
* @param query
* @return
*/
public List<T> find(Query query) {
return mongoTemplate.find(query, entityClass);
}
/**
* 按照字段排序 - 顺序 <br/>
*
* @param query 查询条件 <br/>
* @param properties 排序字段 <br/>
* @return
*/
public List<T> findWithOrderAsc(Query query, String... properties) {
Sort sort = new Sort(Direction.ASC, properties);
query.with(sort);
return mongoTemplate.find(query, entityClass);
}
/**
* 按照字段排序 - 逆序 <br/>
*
* @param query 查询条件 <br/>
* @param properties 排序字段 <br/>
* @return
*/
public List<T> 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<T> findPage(PageInfo<T> 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<T> list = this.find(query);
page.setList(list);
return page;
}
public long count(Query query) {
return mongoTemplate.count(query, entityClass);
}
/**
* 获取collection的名字,默认是dao范型T的名字 <br/>
* 例如: StudentScoreDao extends MongodbDao <b><StudentScore></b> <br/>
* 则返回的名字是:<b>StudentScore</b>
*
* @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<Double> scoreList;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public List<Double> getScoreList() {
return scoreList;
}
public void setScoreList(List<Double> 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<br/>
* 此类对StudentScore对增删改查和分页方法都已经有了<br/>
* @author linhongwei
*/
@Repository
public class StudentScoreDao extends MongodbDao<StudentScore> {
}
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(<id>, 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")))