SpringDataMongoDB-4
Lifecycle Events
SpringData MongoDB提供了几个特殊的事件类型,我们可以继承AbstractMongoEventListener
重写他的方法,或者实现ApplicationListener
接受MongoMappingEvent<?>
事件,就可以做操作了。
由下面的几个事件
- AfterLoadEvent
- AfterDeleteEvent
- BeforeDeleteEvent
- BeforeConvertEvent
- BeforeSaveEvent
- AfterSaveEvent
- AfterConvertEvent
可以重写AbstractMongoEventListener
的方法来重写。
onBeforeConvert
: 在insert,insertList,save 在通过MongoConverter转换之前。onBeforeSave
: insert,insertList,save在保存到数据库之前。onAfterSave
: insert,insertList,save保存之后。onAfterLoad
: find,findAndRemove,findOne从数据库拿到数据之后。onAfterConvert
: 在Document对象转换为POJO对象之后。
在AbstractMongoEventListener中提供了基本的打日志的功能。实现它,并且添加到Spring中就可以用了。如果需要就重写对应的方法。
Session
在MongoDB3.6版本之后,支持Session了,Session可以保证一个session里面的命令是按照执行的顺序来的。这样可以保证数据的一致性保证。这里说的是Sesison是客户端session。
@Test
public void testFind11(){
// 创建sessio选项
ClientSessionOptions sessionOptions = ClientSessionOptions.builder()
.causallyConsistent(true)
.build();
// 通过mongoTemplate来创建session,
Student execute = mongoTemplate.withSession(sessionOptions)
.execute(new SessionCallback<Student>() {
@Override
public Student doInSession(MongoOperations action) {
先查询
Query query = Query.query(Criteria.where("name").is("小红"));
Student one = action.findOne(query, Student.class);
// 在创建一个,插入
Student student = new Student()
.setName(one.getName() + ":" + one.getName())
.setScore(one.getScore())
.setBook(one.getBook())
.setAge(one.getAge());
action.insert(student);
return one;
}
});
System.out.println(execute);
}
事务
使用TransactionTemplate
操作,或者使用@Transaction
注解。
Spring的事务抽象的很好,只要有专门的AbstractPlatformTransactionManager
就可以实现事务的功能。SpringMongoDB也支持这样的功能,支持标准的Spring的事务。如果@Transaction
注解控制不太灵活,就可以用TransactionTemplate
来做。
-
配置专门的
AbstractPlatformTransactionManager
( MongoTransactionManager)@Bean public MongoTransactionManager transactionManager(MongoDatabaseFactory mongoDatabaseFactory) { return new MongoTransactionManager(mongoDatabaseFactory); }
-
使用
-
直接用@Transaction注解
-
使用
TransactionTemplate
来更加精细化的控制。它的原理就是把
TransactionInterceptor
里面的Object invoke(MethodInvocation invocation)
单独的拿了出来。并且将执行的地方通过回调函数来留给调用方来实现。它需要AbstractPlatformTransactionManager
@Test public void testTransaction() { // 通过MongoTransactionManager来创建TransactionTemplate。 // mongoTransactionManager是通过@Autowired注入的。 TransactionTemplate txTemplate = new TransactionTemplate(mongoTransactionManager); // 通过execute方法来做事务的执行。 txTemplate.execute(new TransactionCallbackWithoutResult() { @Override protected void doInTransactionWithoutResult(TransactionStatus status) { List<Student> all = mongoTemplate.findAll(Student.class); System.out.println(all.get(0)); } }); }
execute方法需要
TransactionCallback
的参数,Spring提供了TransactionCallbackWithoutResult
的抽象类,增加了没有返回值的方法。上面的例子就是使用的是TransactionCallbackWithoutResult
-
对Repositories的一些补充
Repositories
Repositories在使用的时候需要在配置类上增加EnableMongoRepositories
,并且指定它的扫描的包,如果没有指定扫描包,默认就扫描配置类所在的包,也可以继承AbstractMongoClientConfiguration
来指定包
- 继承
AbstractMongoClientConfiguration
@Configuration
@EnableMongoRepositories
class ApplicationConfig extends AbstractMongoClientConfiguration {
@Override
protected String getDatabaseName() {
return "e-store";
}
@Override
protected String getMappingBasePackage() {
return "com.oreilly.springdata.mongodb";
}
}
-
直接使用配置类
@Configuration @EnableMongoRepositories class ApplicationConfig{ }
在SpringBoot中可以不用显式的标注。因为它已经搞好了自动配置类。
查询
查询方法前面说过,继承于CrudRepositories,也可以写满足SpringData MongoDB语法规则的方法,我们不需要直接这些方法,它会自动帮我们生成。还可以自己写Repositories的实现类,但是不需要实现接口,方法签名和接口里面规定的一样,实现类的名字是接口的名字+Impl(默认),也可以完成这样的需要。这里需要增加一种,还支持在接口的方法上面增加注解来实现。下面详细的说说这几种方式
-
写满足SpringData MongoDB语法规则的方法
只要满足规则就可以,但是里面也定义了一些关键字,具体看 Supported keywords for query methods-官网,
同样SpringData MongoDB也支持地理位置的查询,这里就不详细介绍了,具体的可以看Geo-spatial Repository Queries
-
可以通过注解类来自定义操作
支持的操作有,删除,count,exist,查询。
添加
org.springframework.data.mongodb.repository.Query
注解在repository的查询方法上,就可以使用原生的mongoDB的语法来做操作,如下:public interface StudentCrudRepository extends MongoRepository<Student, String> { // 使用原生的方法 Student findStudentByName(String name); // 使用query注解,value表示查询的内容,fields表示要字段展示 @Query(value = "{name:?0,age:?1}", fields = "{name:1,age:1}") Student customerFindStudentByNameAndAge(String name, int age); // 增加了sort的排序,这里的语法都是和mongoDB上的一样的,只是将需要参数传递的部分变为占位符 @Query(value = "{\n" + " $or:[\n" + " {name:?0},\n" + " {age:?1}\n" + " ]\n" + "}", fields = "{\n" + " name:1,\n" + " age:1\n" + "}", sort = "{\n" + " name:1,\n" + " age:1\n" + "}") List<Student> findByNameAndAge(String name, int age); // 查询删除 @DeleteQuery(value = "{_id:?0}") String deleteId(String id); // count查询 @CountQuery("{name:?0}") int countName(String name); }
例子中的
?0
表示占位符,可以利用它来替换json查询语句。参数的下标从0开始
占位符可以使用 SpEL,那就可以用函数,调用方法了,进一步的对参数做处理。
SPEL暴露参数是包装在一个数组里面,下标从0开始
@Query("{name:?#{[0]}}")
List<Student> findStudentsByName(String name); // 取第一个数据
@Query("{name:?#{ [0].replace(\"红\",\"粉\") }}") // 调用string的replace方法,将小红替换为小粉
List<Student> findStudentsByName1(String name);
测试类
@Test
void testDeleteCustomer4() {
System.out.println(studentCrudRepository.countName("小红"));
}
@Test
void testDeleteCustomer5() {
studentCrudRepository.findStudentsByName1("小红").forEach(System.out::println);
}
-
聚合操作
聚合操作也是有注解的,
org.springframework.data.mongodb.repository.Aggregation
相应的实例代码在Aggregation Repository Methods-官网
因为聚合操作有限制,限制为100M,SpringData MongoDB提供了
org.springframework.data.mongodb.repository.Meta
,来设置属性。如下:
SpringData MongoDB 就介绍到这里了。文章的内容都是参考官网,写的不全,要是有不理解的地方以官网为准。
关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢。