文章目录
一、MongoDB简介
MongoDB(来自于英文单词“Humongous”,中文含义为“庞大”)是可以应用于各种规模的企业、各个 行业以及各类应用程序的开源数据库。基于分布式文件存储的数据库。由C++语言编写。旨在为WEB应 用提供可扩展的高性能数据存储解决方案。MongoDB是一个高性能,开源,无模式的文档型数据库,是当前NoSql数据库中比较热门的一种。
MongoDB 是专⻔为可扩展性、⾼性能和⾼可⽤性⽽设计的数据库,它可以从单服务器部署扩展到⼤型、复杂的多数据中⼼架构。利⽤内存计算的优势,MongoDB 能够提供⾼性能的数据读写操作。MongoDB 的本地复制和⾃动故障转移功能使应⽤程序具有企业级的可靠性和操作灵活性。
1、MongoDB相关概念
MongoDB 是一个面向文档存储的数据库,看一下与关系型数据库相比,MongoDB的相关概念:
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column | field | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
对比关系图:
2、创建数据库
- 查看所有数据库
show dbs
- 创建数据库
use test
- 为数据库创建用户
db.createUser({user:"test", pwd:"test", roles:[{role:"dbOwner", db:"test"}]})
二、整合MongoDB
Spring Boot 操作数据库的各种 Starters 都继承于 Spring Data,Spring Data 是 Spring 为了简化数据库操作⽽封装的⼀个组件包,提供了操作多种数据库的⽀持,其 API 简洁、调⽤⽅便。
spring-boot-starter-data-mongodb 是 Spring Data 的⼀个⼦模块。⽬标是为 MongoDB 提供⼀个相近的、⼀致的、基于 Spring 的编程模型。spring-boot-starter-data-mongodb 核⼼功能是映射 POJO 到 Mongo 的DBCollection 中的⽂档,并且提供 Repository ⻛格数据访问层。
使⽤ Spring Boot 进⾏ MongoDB 连接,需要使⽤ spring-boot-starter-data-mongodb 包。spring-bootstarter-data-mongodb 继承 Spring Data 的通⽤功能外,针对 MongoDB 的特性开发了很多定制的功能,让使⽤ Spring Boot 操作 MongoDB 更加简便。
Spring Boot 操作 MongoDB 有两种⽐较流⾏的使⽤⽅法:
- 将 MongoTemplate 直接注⼊到 Dao 中使⽤
- ⼀继承 MongoRepository,MongoRepository 内置了很多⽅法可直接使⽤。
1、MongoTemplate
MongoTemplate 提供了⾮常多的操作 MongoDB ⽅法,它是线程安全的,可以在多线程的情况下使⽤。
MongoTemplate 实现了 MongoOperations 接⼝, 此接⼝定义了众多的操作⽅法如 find、findAndModify、findOne、insert、remove、save、update and updateMulti 等。它转换 domain object 为 DBObject,并提供了 Query、Criteria and Update 等流式 API。
1.1、添加依赖
添加 spring-boot-starter-data-mongodb 包引⽤:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
1.2、application.properties配置
在application.properties添加mongodb连接配置:
spring.data.mongodb.uri=mongodb://test:test@localhost:27017/test
如果是集群:
spring.data.mongodb.uri=mongodb://user:pwd@ip1:port1,ip2:port2/database
密码和⽤户名如果没有设置可以不⽤添加:
spring.data.mongodb.uri=mongodb://localhost:27017/test
1.3、创建数据实体
创建数据实体类:
public class User implements Serializable { private static final long serialVersionUID = -3258839839160856613L; private Long id; private String userName; private String passWord; //getter、setter 省略 }
1.4、对实体进⾏增删改查操作
Repository 层实现了 User 对象的增、删、改、查功能。
- 接口:
public interface UserRepository { public void saveUser(User user); public User findUserByUserName(String userName); public long updateUser(User user); public void deleteUserById(Long id); }
- 实现类:
在实现类中使用MongoTemplate对MongoDB进行增删改查的操作。
@Component public class UserRepositoryImpl implements UserRepository { //注入MongoTemplate @Autowired private MongoTemplate mongoTemplate; /** * 添加数据 * save ⽅法中会进⾏判断,如果对象包含了 ID 信息就会进⾏更新,如果没有包含 ID 信息就⾃动保存。 * @param user */ @Override public void saveUser(User user) { mongoTemplate.save(user); } /** * 根据⽤户名查询对象 * @param userName * @return */ @Override public User findUserByUserName(String userName) { Query query=new Query(Criteria.where("userName").is(userName)); User user = mongoTemplate.findOne(query , User.class); return user; } /** * 更新对象 * 可以选择更新⼀条数据,或者更新多条数据 * @param user * @return */ @Override public long updateUser(User user) { Query query=new Query(Criteria.where("id").is(user.getId())); Update update= new Update().set("userName", user.getUserName()).set("passWord" , user.getPassWord()); //更新查询返回结果集的第⼀条 UpdateResult result =mongoTemplate.updateFirst(query,update,User.class); //更新查询返回结果集的所有 // mongoTemplate.updateMulti(query,update,UserEntity.class); if(result!=null) return result.getMatchedCount(); else return 0; } /** * 删除对象 * @param id */ @Override public void deleteUserById(Long id) { Query query=new Query(Criteria.where("id").is(id)); mongoTemplate.remove(query,User.class); } }
1.5、测试
@RunWith(SpringRunner.class) @SpringBootTest public class UserRepositoryTest { @Autowired private UserRepository userRepository; @Test public void testSaveUser(){ User user =new User(2l,"zhangtiegang","gougang"); userRepository.saveUser(user); } @Test public void findUserByUserName(){ User user= userRepository.findUserByUserName("zhangtiegang"); System.out.println("user is "+user); } @Test public void updateUser(){ User user =new User(2l,"wangchunhua","chuanhua"); userRepository.updateUser(user); } @Test public void testDeleteUserById(){ userRepository.deleteUserById(2l); } }
1.6、验证结果
可通过图形化工具或者命令行来查看MongoDB数据库中的数据:
- 切换到test数据库:
use test
- 查询 userEntity 集合数据:
db.user.find()
2、MongoRepository
MongoRepository 继承于 PagingAndSortingRepository,再往上就是 CrudRepository, MongoRepository 和JPA、Elasticsearch 的使⽤⽐较类似,都是 Spring Data 家族的产品,最终使 ⽤⽅法也就和 JPA、ElasticSearch 的使⽤⽅式类似,可以根据⽅法名⾃动⽣成 SQL 来查询。
MongoRepository类图
和MongoTemplate相同,有区别的只是只有 Repository 层。
2.1、UserRepository
新建 UserRepository 需要继承 MongoRepository,这样就可直接使⽤ MongoRepository 的内置⽅法
public interface UserRepository extends MongoRepository<User,Long> { User findByUserName(String userName); //分页查询 Page<User> findAll(Pageable var1); }
2.2、测试
使⽤ UserRepository 进⾏增、删、改、查功能。
@RunWith(SpringRunner.class) @SpringBootTest public class UserRepositoryTest { @Autowired private UserRepository userRepository; /** * 测试保存 * 循环保存多个user * @throws Exception */ @Test public void testSaveUser() throws Exception { for (long i=0;i<100;i++) { User user=new User(); user.setId(i); user.setUserName("san"+i); user.setPassWord("shisanbushier"); userRepository.save(user); } } /** * 测试保存 * 保存单个user * @throws Exception */ @Test public void testSingleSaveUser() throws Exception { User user=new User(1l,"san","chuizi"); userRepository.save(user); } /** * 测试查找 */ @Test public void findUserByUserName(){ User user= userRepository.findByUserName("san"); System.out.println("user is "+user); } @Test public void updateUser(){ User user=new User(); user.setId(1l); user.setUserName("er"); user.setPassWord("shierbushisan"); userRepository.save(user); } /** * 测试删除 */ @Test public void deleteUserById(){ userRepository.deleteById(1l); } /** * 测试分页查看 */ @Test public void testPage(){ Pageable pageable = PageRequest.of(2, 10); Page page=userRepository.findAll(pageable); System.out.println("users: "+page.getContent().toString()); } }
- Pageable 是 Spring Data 库中定义的⼀个接⼝,该接⼝是所有分⻚相关信息的⼀个抽象,通过该接⼝,可以得到和分⻚相关所有信息(如 pageNumber、pageSize 等),这样,JPA 就能够通过 pageable 参数来得到⼀个带分⻚信息的 SQL 语句。
- Page 类也是 Spring Data 提供的⼀个接⼝,该接⼝表示⼀部分数据的集合以及其相关的下⼀部分数据、数据总数等相关信息,通过该接⼝,可以得到数据的总体信息(数据总数、总⻚数…)以及当前数据的信息(当前数据的集合、当前⻚数等)。
2.3、验证
验证同上,可以通过可视化工具或命令行。
上面两种⽅式都可以⽅便地操作 MongoDB 数据库,MongoTemplate 模式⽐较灵活可以根据⾃⼰的使⽤情况进⾏组装,MongoRepository 的使⽤⽅式更简单,因为继承了 Spring Data,所以默认实现了很多基础的增、删、改、查功能,业务直接拿来使⽤即可。简单⽇常的使⽤推荐 MongoRepository,简单⽅便利于项⽬快速开发,复杂多变的查询推荐使⽤ MongoTemplate ⾃⾏进⾏封装。
3、MongoDB多数据源
3.1、添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
3.2、application.properties配置
在配置⽂件中添加不同的数据源:
mongodb.primary.uri=mongodb://localhost:27017 mongodb.primary.database=primary mongodb.secondary.uri=mongodb://localhost:27017 mongodb.secondary.database=secondary
集群可以采用以下配置:
mongodb.xxx.uri=mongodb://192.168.0.1:27017,192.168.0.2:27017,192.168.0.3:27017 mongodb.xxx.database=xxx
3.3、配置数据源
- 封装读取以 Mongodb 开头的两个配置文件:
@ConfigurationProperties(prefix = "mongodb") public class MultipleMongoProperties { private MongoProperties primary = new MongoProperties(); private MongoProperties secondary = new MongoProperties(); //省略 getter、setter }
- 创建 MultipleMongoConfig 类分别创建两个数据源的 MongoTemplate:
Configuration public class MultipleMongoConfig { @Autowired private MultipleMongoProperties mongoProperties; /** * 利⽤构建好的 MongoDbFactory 创建对应的 MongoTemplate * @return * @throws Exception */ @Primary @Bean(name = "primaryMongoTemplate") public MongoTemplate primaryMongoTemplate() throws Exception { return new MongoTemplate(primaryFactory(this.mongoProperties.getPrimary())); } @Bean @Qualifier("secondaryMongoTemplate") public MongoTemplate secondaryMongoTemplate() throws Exception { return new MongoTemplate(secondaryFactory(this.mongoProperties.getSecondary())); } /** * 根据配置⽂件信息构建第⼀个数据源的 MongoDbFactory * @param mongo * @return * @throws Exception */ @Bean @Primary public MongoDbFactory primaryFactory(MongoProperties mongo) throws Exception { MongoClient client = new MongoClient(new MongoClientURI(mongoProperties.getPrimary().getUri())); return new SimpleMongoDbFactory(client, mongoProperties.getPrimary().getDatabase()); } @Bean public MongoDbFactory secondaryFactory(MongoProperties mongo) throws Exception { MongoClient client = new MongoClient(new MongoClientURI(mongoProperties.getSecondary().getUri())); return new SimpleMongoDbFactory(client, mongoProperties.getSecondary().getDatabase()); } }
- 配置不同包路径下使用不同的数据源
第一个库的封装:
@Configuration @EnableConfigurationProperties(MultipleMongoProperties.class) @EnableMongoRepositories(basePackages = "edu.hpu.repository.primary", mongoTemplateRef = "primaryMongoTemplate") public class PrimaryMongoConfig { }
第二个库的封装:
@Configuration @EnableMongoRepositories(basePackages = "edu.hpu.repository.secondary", mongoTemplateRef = SecondaryMongoConfig.MONGO_TEMPLATE) public class SecondaryMongoConfig { protected static final String MONGO_TEMPLATE = "secondaryMongoTemplate"; }
3.4、实体类
public class User implements Serializable { private static final long serialVersionUID = -3258839839160856613L; private String id; private String userName; private String passWord; //省略getter setter }
3.5、Repository
在edu.hpu.repository.primary、edu.hpu.repository.secondary包下分别创建两个Repository。
public interface PrimaryRepository extends MongoRepository<User, String> { }
public interface SecondaryRepository extends MongoRepository<User,String> { }
3.6、测试
@RunWith(SpringRunner.class) @SpringBootTest public class RepositoryTest { @Autowired private PrimaryRepository primaryRepository; @Autowired private SecondaryRepository secondaryRepository; @Test public void TestSave() { //分别向两个库中存入数据 this.primaryRepository.save(new User("01","张三", "123456")); this.secondaryRepository.save(new User("02","李四", "654321")); //从第一个库中取出数据 List<User> primaries = this.primaryRepository.findAll(); for (User primary : primaries) { System.out.println(primary.toString()); } //从第二个库中取出数据 List<User> secondaries = this.secondaryRepository.findAll(); for (User secondary : secondaries) { System.out.println(secondary.toString()); } } }
运行结果:
通过可视化工具或命令行同样可以在对应的库中查到数据。