SpringDataMongoDB-4(完结)

357 阅读5分钟

SpringDataMongoDB-4

Lifecycle Events

SpringData MongoDB提供了几个特殊的事件类型,我们可以继承AbstractMongoEventListener 重写他的方法,或者实现ApplicationListener接受MongoMappingEvent<?>事件,就可以做操作了。

由下面的几个事件

  1. AfterLoadEvent
  2. AfterDeleteEvent
  3. BeforeDeleteEvent
  4. BeforeConvertEvent
  5. BeforeSaveEvent
  6. AfterSaveEvent
  7. AfterConvertEvent

可以重写AbstractMongoEventListener的方法来重写。

  • onBeforeConvert: 在insert,insertList,save 在通过MongoConverter转换之前。
  • onBeforeSave: insert,insertList,save在保存到数据库之前。
  • onAfterSave: insert,insertList,save保存之后。
  • onAfterLoad: find,findAndRemove,findOne从数据库拿到数据之后。
  • onAfterConvert: 在Document对象转换为POJO对象之后。

在AbstractMongoEventListener中提供了基本的打日志的功能。实现它,并且添加到Spring中就可以用了。如果需要就重写对应的方法。

image-20220501101558220.png

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来做。

  1. 配置专门的AbstractPlatformTransactionManager( MongoTransactionManager)

       @Bean
        public MongoTransactionManager transactionManager(MongoDatabaseFactory mongoDatabaseFactory) {
            return new MongoTransactionManager(mongoDatabaseFactory);
        }
    
  2. 使用

    1. 直接用@Transaction注解

    2. 使用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的一些补充

MongoDB 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(默认),也可以完成这样的需要。这里需要增加一种,还支持在接口的方法上面增加注解来实现。下面详细的说说这几种方式

  1. 写满足SpringData MongoDB语法规则的方法

    只要满足规则就可以,但是里面也定义了一些关键字,具体看 Supported keywords for query methods-官网,

    同样SpringData MongoDB也支持地理位置的查询,这里就不详细介绍了,具体的可以看Geo-spatial Repository Queries

  2. 可以通过注解类来自定义操作

    支持的操作有,删除,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);
    }

image-20220502132530086.png

  1. 聚合操作

    聚合操作也是有注解的,org.springframework.data.mongodb.repository.Aggregation

    相应的实例代码在Aggregation Repository Methods-官网

    因为聚合操作有限制,限制为100M,SpringData MongoDB提供了org.springframework.data.mongodb.repository.Meta,来设置属性。如下:

image-20220502134609948.png

SpringData MongoDB 就介绍到这里了。文章的内容都是参考官网,写的不全,要是有不理解的地方以官网为准。


关于博客这件事,我是把它当做我的笔记,里面有很多的内容反映了我思考的过程,因为思维有限,不免有些内容有出入,如果有问题,欢迎指出。一同探讨。谢谢。