文章目錄
MongoDB(來自于英文單詞“Humongous”,中文含義為“龐大”)是可以應用于各種規模的企業、各個 行業以及各類應用程式的開源資料庫。基于分布式檔案存儲的資料庫。由C++語言編寫。旨在為WEB應 用提供可擴充的高性能資料存儲解決方案。MongoDB是一個高性能,開源,無模式的文檔型資料庫,是目前NoSql資料庫中比較熱門的一種。
MongoDB 是專⻔為可擴充性、⾼性能和⾼可⽤性⽽設計的資料庫,它可以從單伺服器部署擴充到⼤型、複雜的多資料中⼼架構。利⽤記憶體計算的優勢,MongoDB 能夠提供⾼性能的資料讀寫操作。MongoDB 的本地複制和⾃動故障轉移功能使應⽤程式具有企業級的可靠性和操作靈活性。
MongoDB 是一個面向文檔存儲的資料庫,看一下與關系型資料庫相比,MongoDB的相關概念:
SQL術語/概念 | MongoDB術語/概念 | 解釋/說明 |
database | 資料庫 | |
table | collection | 資料庫表/集合 |
row | document | 資料記錄行/文檔 |
column | field | 資料字段/域 |
index | 索引 | |
table joins | 表連接配接,MongoDB不支援 | |
primary key | 主鍵,MongoDB自動将_id字段設定為主鍵 |
對比關系圖:
- 檢視所有資料庫
show dbs
- 建立資料庫
use test
- 為資料庫建立使用者
db.createUser({user:"test", pwd:"test", roles:[{role:"dbOwner", db:"test"}]})
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 内置了很多⽅法可直接使⽤。
MongoTemplate 提供了⾮常多的操作 MongoDB ⽅法,它是線程安全的,可以在多線程的情況下使⽤。
MongoTemplate 實作了 MongoOperations 接⼝, 此接⼝定義了衆多的操作⽅法如 find、findAndModify、findOne、insert、remove、save、update and updateMulti 等。它轉換 domain object 為 DBObject,并提供了 Query、Criteria and Update 等流式 API。
添加 spring-boot-starter-data-mongodb 包引⽤:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
在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
建立資料實體類:
public class User implements Serializable {
private static final long serialVersionUID = -3258839839160856613L;
private Long id;
private String userName;
private String passWord;
//getter、setter 省略
}
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);
}
}
@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);
}
}
可通過圖形化工具或者指令行來檢視MongoDB資料庫中的資料:
- 切換到test資料庫:
use test
- 查詢 userEntity 集合資料:
db.user.find()
MongoRepository 繼承于 PagingAndSortingRepository,再往上就是 CrudRepository, MongoRepository 和JPA、Elasticsearch 的使⽤⽐較類似,都是 Spring Data 家族的産品,最終使 ⽤⽅法也就和 JPA、ElasticSearch 的使⽤⽅式類似,可以根據⽅法名⾃動⽣成 SQL 來查詢。
MongoRepository類圖
和MongoTemplate相同,有差別的隻是隻有 Repository 層。
建立 UserRepository 需要繼承 MongoRepository,這樣就可直接使⽤ MongoRepository 的内置⽅法
public interface UserRepository extends MongoRepository<User,Long> {
User findByUserName(String userName);
//分頁查詢
Page<User> findAll(Pageable var1);
}
使⽤ 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 提供的⼀個接⼝,該接⼝表示⼀部分資料的集合以及其相關的下⼀部分資料、資料總數等相關資訊,通過該接⼝,可以得到資料的總體資訊(資料總數、總⻚數…)以及目前資料的資訊(目前資料的集合、目前⻚數等)。
驗證同上,可以通過可視化工具或指令行。
上面兩種⽅式都可以⽅便地操作 MongoDB 資料庫,MongoTemplate 模式⽐較靈活可以根據⾃⼰的使⽤情況進⾏組裝,MongoRepository 的使⽤⽅式更簡單,因為繼承了 Spring Data,是以預設實作了很多基礎的增、删、改、查功能,業務直接拿來使⽤即可。簡單⽇常的使⽤推薦 MongoRepository,簡單⽅便利于項⽬快速開發,複雜多變的查詢推薦使⽤ MongoTemplate ⾃⾏進⾏封裝。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
在配置⽂件中添加不同的資料源:
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
- 封裝讀取以 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";
}
public class User implements Serializable {
private static final long serialVersionUID = -3258839839160856613L;
private String id;
private String userName;
private String passWord;
//省略getter setter
}
在edu.hpu.repository.primary、edu.hpu.repository.secondary包下分别建立兩個Repository。
public interface PrimaryRepository extends MongoRepository<User, String> {
}
public interface SecondaryRepository extends MongoRepository<User,String> {
}
@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());
}
}
}
運作結果:
通過可視化工具或指令行同樣可以在對應的庫中查到資料。