因为疫情的原因加上自己个人私事也比较多,有好一段时间没有写东西了,趁着这周有时间准备学习点新的东西。公司的项目已经在开发当中了,接口写了不少但是都还没有测过。过年及年后那段时间一直在鼓捣Docker和k8s,自己也写了一点文档,因为比较凌乱,所以暂时就没有发布出来,后期有时间在弄吧。今天想了想也不知道写点什么,思来想去,感觉看看mogondb吧,mongodb也是自己很久之前都想了解和学习的,记得那时候mongodb版本才刚开始支持ACID。好了,闲话少说,开始吧!
一、安装
mongodb从官方地址直接根据系统下载,我是linux系统,下载之后解压。并将可执行文件添加到PATH:
## 添加mogodb到PATH
export PATH=/bin:$PATH
根据需要创建数据存储路径
mkdir -p /home/ypcfly/ypcfly/software/MongoDB/mongodb/data
另外创建自定义了配置文件:mongodb.conf
port=27017
dbpath=/home/ypcfly/ypcfly/software/MongoDB/mongodb/data
logpath=/home/ypcfly/ypcfly/software/MongoDB/mongodb/logs/mongodb.log
pidfilepath=/home/ypcfly/ypcfly/software/MongoDB/mongodb/mongo.pid
fork=true
logappend=true
#auth=true
之后进入到bin目录下,启动mongodb并指定加载的配置文件
./mongod --config /home/ypcfly/ypcfly/software/MongoDB/mongodb/mongodb.conf
接着在bin目录下执行命令,进入到控制台
./mongo
mongodb的命令也不复杂,就是写起来没有SQL那么顺手,常用的命令也就那些,这里不做过多的介绍。首先创建一个用户并创建一个database。
切换到admin数据库
use admin ##然后创建一个管理员
switched to db admin
## 创建管理员
db.createUser({user:"root",pwd:"123456",roles:[roles:"root"]
db.auth('root','123456')
## 创建一个数据库和数据库用户
use mongon_db
switched to db mongon_db
##创建mongo_db的管理员
db.createUser({user:"ypcfly",pwd:"123456",roles:[{role:"dbOwner",db:"mongo_db"}]})
##创建一个user表
db.createCollection("user")
mongondb的用法我觉得还是要在使用的过程中去学,而不是单独的为学而学。以上完成之后我们通过spring boot来使用一下mongodb。
二、spring boot整合mongodb
创建一个spring boot项目,引入mongodb的依赖:spring-boot-starter-data-mongodb。
另外说一点就是idea的database工具目前是支持mongodb的,所以我直接通过database工具连接mongodb。
项目引入mongodb的依赖之后需要在项目中进行配置:
server.port=11000
spring.application.name=mongodb-test
spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017
spring.data.mongodb.database=mongo_db
spring.data.mongodb.username=ypcfly
spring.data.mongodb.password=123456
## 使用URI
#spring.data.mongodb.uri=mongodb://localhost:27017/mongo_db
配置中可以使用uri的方式加上用户名和密码,或者就是host加端口号加数据库名称,这个就看个人的喜好了。之后启动项目,一切正常。
接下来就要对mongodb做一些CRUD了,按照传统的关系型数据库一个表一般都会对应着一个或多个java的实体类。所以我们先创建一个简单的实体类-User以便对数据库进行操作,代码如下:
@Data
@Document(value = "user")
public class User {
private String id;
private String userName;
private Integer age;
private String sex;
private String address;
private String mobile;
}
@Document
注解的值就是表示这个类对应着mongodb中的一个Collection,用传统关系型数据库来对比就是Table。就像spring-data-jpa中的@Entity
注解一样。创建好数据模型之后,接下来就是对数据库进行CRUD。如果对spring比较熟悉的话都应该知道spring data对数据库的操作一般都提供了两种方式,一种是模板,比如JDBCTemplate
、ElasticsearchTemplate
甚至RedisTemplate
,另外一种就是Repository,比如ElasticsearchRepository
等等。同样mongodb也为我们提供了这两种方式,接下来我们通过小的demo简单的了解一下。
三、demo演示
在第一步中我们创建好user表(collection)之后里面还没有任何的数据,我们先创建好相应的Controller、Service,这里就不再贴代码了。
创建UserRepository
public interface UserRepository extends MongoRepository {
}
在Service的实现类当中我们需要注入MongoTemplate
和UserRepository
。这里说个题外话,最近在使用idea的过程当中采用属性注入bean会有提示说:Field injection is not recommended ,即不推荐使用属性方式注入,自己也网上看了下,确实目前一般推荐使用构造注入或set方法注入的方式,自己这个习惯还是跟着改一下。创建Service的实现类,代码如下:
@Slf4j
@Service
public class MongoDBServiceImpl implements MongoDBService {
private static final Gson GSON = new Gson();
private MongoTemplate mongoTemplate;
private UserRepository userRepository;
@Autowired
public void setMongoTemplate(MongoTemplate mongoTemplate) {
this.mongoTemplate = mongoTemplate;
}
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public User insert(User user) {
User result = mongoTemplate.insert(user,"user");
// User result = userRepository.insert(user);
log.info(">>>> result={} <<<<",GSON.toJson(result));
return result;
}
@Override
public User update(User user) {
User result = mongoTemplate.save(user);
// User result = userRepository.save(user);
log.info(">>>> result={} <<<<",GSON.toJson(result));
return result;
}
@Override
public List query(User user) {
ExampleMatcher matcher = ExampleMatcher.matching()
.withMatcher("age",ExampleMatcher.GenericPropertyMatchers.exact())
.withMatcher("userName",ExampleMatcher.GenericPropertyMatchers.exact())
.withMatcher("address",ExampleMatcher.GenericPropertyMatchers.contains());
Example example = Example.of(user,matcher);
List userList = userRepository.findAll(example, Sort.by(Sort.Order.desc("age")));
userList = mongoTemplate.find(Query.query(Criteria.byExample(user)).with(Sort.by(Sort.Order.asc("age"))),User.class);
return userList;
}
@Override
public Boolean delete(String id) {
// 根据id删除
userRepository.deleteById(id);
DeleteResult deleteResult = mongoTemplate.remove(Query.query(Criteria.where("id").is(id)),User.class);
log.info(">>>> delete count={} <<<<",deleteResult.getDeletedCount());
return Boolean.TRUE;
}
根据上面的代码不难发现不管是MongoTemplate
和MongoRepository
提供的基本的功能都比较接近,MongoTemplate
提供的方法更多且更偏向于底层;MongoRepository
封装的更好一些。就简单的操作来看个人感觉使用MongoRepository
更好一些。
通过使用http调用一下我们的CRUD接口发现都没有问题,这里就不贴相关代码了。这里说一下mongodb的主键问题,mongodb使用的主键是ObjectId,它通过时间戳+机器标识+进程ID+自增计数器生成的,在上面的User实体类中我并没有在id属性上加@Id
注解,但是这并不影响mongodb中id的生成。这点和使用spring-data-jpa还是有点区别的。
最后说一个自己踩的坑,在条件查询的时候我在调用接口时传入的参数字符串都是"",导致在查询的时候查询不出数据,当时自己很奇怪,是不是自己哪里的姿势不正确,后来debug才意识到,如果根据""是查询不出数据的,因为之前都是将用户传入的DTO转成Entity的,所以传入""一般不影响后面使用Entity进行查询,但是今天我是直接用Entity接受参数并查询的,导致数据查询出问题。
通过上面的demo我发现使用了MongoRepository
好像语法也没那么重要了,mongodb怎么进行查询?不知道,反正有MongoRepository
,简单的功能使用起来真的挺简单,但是我语法还是要去学习一下的,另外mongodb一些重要特性比如索引、ACID等等,后期有时间在看。