在 NoSQL
盛行的时代,App很大可能会涉及到MongoDB数据库的使用,而也必须学会在 Spring boot
使用 Spring Data
连接 MongoDB
进行数据增删改查操作,如下为详细的操作手册。
直接导入 spring-data-mongodb
包或者使用 Spring Boot starter
<dependencies> <!-- other dependency elements omitted --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-mongodb</artifactId> <version>2.2.0.RELEASE</version> </dependency> </dependencies> <!--spring 框架使用最新的 --> <spring.framework.version>5.2.0.RELEASE</spring.framework.version> <!--用一即可--> <!--使用Spring Boot starter--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency>
#mongodb连接地址,集群用“;”隔开 spring.mongo.mongoDatabaseAddress=10.110.112.165:27092;10.110.112.166:27092 #mongo数据名 spring.mongo.dbname=mongodb #mongo用户 spring.mongo.username=mongodbopr #mongo密码 spring.mongo.password=123456 #mongo最大连接数 spring.mongo.connectionsPerHost=50
注册 Mongo
实例配置:
@Configuration public class MongodbConfig { public static final String COMMA = ";"; public static final String COLON = ":"; @Value("${spring.mongo.mongoDatabaseAddress}") private String mongoDatabaseAddress; @Value("${spring.mongo.username}") private String username; @Value("${spring.mongo.dbname}") private String dbname; @Value("${spring.mongo.password}") private String password; @Value("${spring.mongo.connectionsPerHost}") private String connectionsPerHost; /** * 获取mongodb的地址 * * @return */ private List<ServerAddress> getMongoDbAddress() { List<ServerAddress> serverAddrList = new ArrayList<ServerAddress>(); //如果有多个服务器的话 if (this.mongoDatabaseAddress.indexOf(COMMA) > 0) { String[] addressArrays = mongoDatabaseAddress.split(COMMA); String[] hostPort; for (String address : addressArrays) { hostPort = address.split(COLON); ServerAddress serverAdress = new ServerAddress(hostPort[0], Integer.valueOf(hostPort[1])); serverAddrList.add(serverAdress); } } else { String[] hostPort = mongoDatabaseAddress.split(COLON); ServerAddress serverAdress = new ServerAddress(hostPort[0], Integer.valueOf(hostPort[1])); serverAddrList.add(serverAdress); } return serverAddrList; } /** * 设置连接参数 */ private MongoClientOptions getMongoClientOptions() { MongoClientOptions.Builder builder = MongoClientOptions.builder(); // todo 添加其他参数配置 //最大连接数 builder.connectionsPerHost(Integer.valueOf(connectionsPerHost)); MongoClientOptions options = builder.readPreference(ReadPreference.nearest()).build(); return options; } /** * * @return */ @Bean public MongoClient mongoClient() { //使用数据库名、用户名密码登录 MongoCredential credential = MongoCredential.createCredential(username, dbname, password.toCharArray()); //创建Mongo客户端 return new MongoClient(getMongoDbAddress(), credential, getMongoClientOptions()); } /** * 注册mongodb操作类 * @param mongoClient * @return */ @Bean @ConditionalOnClass(MongoClient.class) public MongoTemplate mongoTemplate(MongoClient mongoClient) { MongoTemplate mongoTemplate = new MongoTemplate(new SimpleMongoDbFactory(mongoClient, dbname)); return mongoTemplate; } }
使用 MongoTemplate
类进行增删改查
@Service public class MongodbService { @Autowired private MongoTemplate mongoTemplate; /** * 新增文档 * * @param userDTO * @return */ public UserDTO insert(UserDTO userDTO) { //insert方法并不提供级联类的保存,所以级联类需要先自己先保存 return mongoTemplate.insert(userDTO); } public UserDTO save(UserDTO userDTO) { Sort sort = new Sort(Sort.Direction.DESC, "name"); userDTO = mongoTemplate.findOne(Query.query(Criteria.where("")).with(sort), UserDTO.class); return mongoTemplate.save(userDTO); } /** * 删除文档 * NOTE:remove方法不支持级联删除所以要单独删除子数据 * @param name */ public void remove(String name) { //根据名字查询数据并删除 UserDTO userDTO = mongoTemplate.findOne(Query.query(Criteria.where("name").is(name)), UserDTO.class); //remove方法不支持级联删除所以要单独删除子数据 List<AddressDTO> addressList = userDTO.getAddressList(); for (AddressDTO addressDTO : addressList) { mongoTemplate.remove(addressDTO); } //删除主数据 mongoTemplate.remove(userDTO); } /** * 更新文档 * @param userDTO */ public void update(UserDTO userDTO) { mongoTemplate.updateFirst(Query.query(Criteria.where("name").is(userDTO.getName())), Update.update("age", userDTO.getAge()), UserDTO.class); } /** * 查询文档 * @param name */ public void find(String name) { Sort sort = new Sort(Sort.Direction.DESC, "name"); List<UserDTO> userDTOS = mongoTemplate.find(Query.query(Criteria.where("name").is(name)), UserDTO.class); //基于sort排序使用findOne查询最新一条记录 UserDTO userDTO = mongoTemplate.findOne(Query.query(Criteria.where("name").is(name)).with(sort), UserDTO.class); //模糊查询 List<UserDTO> userDTOList = mongoTemplate.find(Query.query(Criteria.where("name").is(name).regex(name)).with(sort), UserDTO.class); //分页查询 Pageable pageable = PageRequest.of(3, 20, sort); List<UserDTO> userDTOPageableList = mongoTemplate.find(Query.query(Criteria.where("name").is(name)).with(pageable), UserDTO.class); //总数 long conut = mongoTemplate.count(Query.query(Criteria.where("name").is(name)), UserDTO.class); Page<UserDTO> page = new PageImpl(userDTOPageableList, pageable, conut); } }
NOTE:
在开发中,如果从任何 MongoDB
操作返回的 com.mongodb.WriteResult
包含错误,则可以方便地记录或引发异常。 通常,在开发过程中很容易忘记执行此操作,然后最终得到一个看似运行成功的App,但实际上该数据库操作发生异常,没执行成功。 可以将 MongoTemplate
的 WriteResultChecking
属性设置为以下值之一:
EXCEPTION
:引发 Exception
NONE
:不执行任何操作,默认值
对于更高级的情况,可以将每个操作设置不同的 WriteConcern
值(用于删除,更新,插入和保存操作),则可以在 MongoTemplate
上配置 WriteConcernResolver
的策略接口。 由于 MongoTemplate
用于持久化 POJO
,因此 WriteConcernResolver
允许您创建一个策略,该策略可以将特定的 POJO
类映射到 WriteConcern
值。
WriteConcernResolver
接口:
public interface WriteConcernResolver { WriteConcern resolve(MongoAction action); }
自定义 WriteConcernResolver
接口,实现不同 WriteConcern
策略:
private class MyAppWriteConcernResolver implements WriteConcernResolver { public WriteConcern resolve(MongoAction action) { if (action.getEntityClass().getSimpleName().contains("UserDTO")) { return WriteConcern.NONE; } else if (action.getEntityClass().getSimpleName().contains("Metadata")) { return WriteConcern.JOURNAL_SAFE; } return action.getDefaultWriteConcern(); } }
基于 ServerAddress
单机或者 Replica Set
在使用 MongoClient
连接 mongodb
数据库注册 mongo
实例,在注册示例中可能要使得 MongoCredential
账号密码验证以及使用 MongoClientOptions
配置 mongodb
其他的参数。
MongoClient
常用的构造器方法:
public MongoClient(String host){} public MongoClient(MongoClientURI uri){} public MongoClient(String host, MongoClientOptions options) {} public MongoClient(ServerAddress addr, MongoCredential credential, MongoClientOptions options){} public MongoClient(List<ServerAddress> seeds, MongoCredential credential, MongoClientOptions options){}
使用 MongoTemplate
结合 Sort
、 Criteria
、 Query
、 Update
以及分页 Pageable
类灵活地进行对 mongodb
数据库进行增删改查。
query
方法:
//根据查询条件查询 public <T> List<T> find(Query query, Class<T> entityClass){} //根据查询条件查询返回一条记录 public <T> <T>findOne(Query query, Class<T> entityClass){} //查询该collection所有记录 public <T> List<T> findAll(Class<T> entityClass){}
insert
方法:
//新增一条记录 public <T> T insert(T objectToSave){} //在collectionName中新增一条记录 public <T> T insert(T objectToSave, String collectionName) {} // public <T> T save(T objectToSave){}
remove
方法:
//根据Object删除 public DeleteResult remove(Object object) {} //根据查询条件进行删除 public DeleteResult remove(Query query, Class<?> entityClass){}
update
方法:
// public UpdateResult upsert(Query query, Update update, Class<?> entityClass) {} //更新查询出来的第一条记录 public UpdateResult updateFirst(Query query, Update update, String collectionName) {}
Sort
查询排序类。 Sort
类常用方法:
//构造方法创建一个排序。direction为排序方向的枚举类型,properties为排序字段数组 Sort(Sort.Direction direction, String... properties) //多个排序条件链接 and(Sort sort) //返回升序排列对象 ascending() //返回降序排列对象 descending()
Criteria
查询条件类,类似于SQL的where,常用方法:
//声明定义查询条件,且为静态方法 where(String key) //与操作 and(String key) //正则表达式,即可为模糊查询 regex(String re) //包含 in(Object... o) //大于 gt(Object o) //大于等于 gte(Object o) //等于 is(Object o) //小于 lt(Object o) //小于等于 lte(Object o) //非 not() //创建与操作 andOperator(Criteria... criteria)
Query
查询对象,具有查询的全部信息,其中包括筛选条件、排序、返回数量等。常用的方法:
//定义查询对象,静态方法 query(CriteriaDefinition criteriaDefinition) //在本次查询添加一个CriteriaDefinition查询条件 addCriteria(CriteriaDefinition criteriaDefinition) //添加一个Sort排序对象 with(Sort sort) //添加一个Pageable分页对象、通常情况下,分页和排序一起使用。 with(Pageable pageable)
注解 | 解析 |
---|---|
@Id | 用于标记id字段,没有标记此字段的实体也会自动生成id字段,但是我们无法通过实体来获取id。id建议使用ObjectId类型来创建 |
@Document | 用于标记此实体类是mongodb集合映射类 |
@DBRef | 用于指定与其他集合的级联关系,但是需要注意的是并不会自动创建级联集合 |
@Indexed | 用于标记为某一字段创建索引 |
@CompoundIndex | 用于创建复合索引 |
@TextIndexed: | 用于标记为某一字段创建全文索引 |
@Language | 指定documen语言 |
@Transient: | 被该注解标注的,将不会被录入到数据库中。只作为普通的javaBean属性 |
@Field: | 用于指定某一个字段映射到数据库中的名称 |