Spring Data的MongoTemplate和MongoRepository有什么区别?

kkih6yb8  于 2023-04-28  发布在  Spring
关注(0)|答案(3)|浏览(281)

我需要编写一个应用程序,可以使用spring-data和MongoDB进行复杂的查询。我开始使用MongoRepository,但在查找示例或理解语法时,我遇到了复杂的查询。
我说的是这样的查询:

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    List<User> findByEmailOrLastName(String email, String lastName);
}

或者使用基于JSON的查询,我尝试了反复试验,因为我没有得到正确的语法。即使在阅读了MongoDB文档之后(由于语法错误而无法工作的示例)。

@Repository
public interface UserRepositoryInterface extends MongoRepository<User, String> {
    @Query("'$or':[{'firstName':{'$regex':?0,'$options':'i'}},{'lastName':{'$regex':?0,'$options':'i'}}]")
    List<User> findByEmailOrFirstnameOrLastnameLike(String searchText);
}

在阅读了所有文档之后,似乎mongoTemplate的文档比MongoRepository好得多。我指的是以下文档:
http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/
你能告诉我哪一个更方便更强大吗?mongoTemplate还是MongoRepository?两者都是一样成熟还是一个比另一个缺少更多的特征?

fhg3lkii

fhg3lkii1#

“方便”和“功能强大”在某种程度上是相互矛盾的目标。存储库比模板方便得多,但后者当然可以给予您更细粒度地控制要执行的内容。
由于存储库编程模型可用于多个Spring Data模块,您可以在Spring Data MongoDB参考文档的常规部分找到更多深入的文档。

TL;DR

我们通常建议采用以下方法:
1.从存储库抽象开始,使用查询派生机制或手动定义的查询来声明简单的查询。
1.对于更复杂的查询,请将手动实现的方法添加到存储库中(如此处所述)。使用MongoTemplate实现。

详情

对于您的示例,它看起来像这样:
1.为自定义代码定义接口:

interface CustomUserRepository {

  List<User> yourCustomMethod();
}

1.为这个类添加一个实现,并遵循命名约定,以确保我们可以找到这个类。

class UserRepositoryImpl implements CustomUserRepository {

  private final MongoOperations operations;

  @Autowired
  public UserRepositoryImpl(MongoOperations operations) {

    Assert.notNull(operations, "MongoOperations must not be null!");
    this.operations = operations;
  }

  public List<User> yourCustomMethod() {
    // custom implementation here
  }
}

1.现在让你的基本仓库接口扩展自定义接口,基础设施将自动使用你的自定义实现:

interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {

}

这样你基本上就得到了选择:所有容易声明的东西都放在UserRepository中,所有更好地手动实现的东西都放在CustomUserRepository中。此处记录了自定义选项。

06odsfpq

06odsfpq2#

FWIW,关于多线程环境中的更新:

  • MongoTemplate提供**“原子”开箱即用操作**updateFirstupdateMultifindAndModifyupsert。..允许您在单个操作中修改文档。这些方法使用的Update对象也允许您仅针对相关字段
  • MongoRepository只提供基本CRUD操作findinsertsavedelete,适用于包含所有字段的POJO。这迫使您要么分几个步骤更新文档(1.find要更新的文档,2.从返回的POJO中修改相关字段,然后3.save it),或者使用@Query手工定义自己的更新查询。

在多线程环境中,如e。例如,一个Java后端具有多个REST端点,单方法更新是一种方法,以减少两个并发更新覆盖彼此更改的可能性。
例如:给定一个像这样的文档:{ _id: "ID1", field1: "a string", field2: 10.0 }和两个不同的线程并发地更新它。..
使用MongoTemplate,它看起来有点像这样:

THREAD_001                                                      THREAD_002
|                                                               |
|update(query("ID1"), Update().set("field1", "another string")) |update(query("ID1"), Update().inc("field2", 5))
|                                                               |
|                                                               |

并且文档的最终状态总是{ _id: "ID1", field1: "another string", field2: 15.0 },因为每个线程只访问DB一次 * 并且 * 只有指定的字段被更改。
而使用MongoRepository的相同案例场景看起来像这样:

THREAD_001                                                      THREAD_002
|                                                               |
|pojo = findById("ID1")                                         |pojo = findById("ID1")
|pojo.setField1("another string") /* field2 still 10.0 */       |pojo.setField2(pojo.getField2()+5) /* field1 still "a string" */
|save(pojo)                                                     |save(pojo)
|                                                               |
|                                                               |

最终文档是{ _id: "ID1", field1: "another string", field2: 10.0 }还是{ _id: "ID1", field1: "a string", field2: 15.0 },取决于哪个save操作最后命中DB。
(NOTE:即使我们按照注解中的建议使用Spring Data的@Version注解,也不会有太大的改变:save操作中的一个将抛出OptimisticLockingFailureException,并且最终文档仍然是上述操作中的一个,只有一个字段更新,而不是两个。)
所以我认为**MongoTemplate是一个更好的选择**,除非你有一个非常复杂的POJO模型,或者出于某种原因需要MongoRepository的自定义查询功能。

khbbv19g

khbbv19g3#

这个答案可能有点延迟,但我建议避免整个存储库路线。你得到的方法很少有很大的实用价值。为了使它工作,您遇到了Java配置的废话,您可能会花费数天甚至数周的时间,而没有文档中的太多帮助。
相反,使用MongoTemplate路线并创建您自己的数据访问层,这将使您从Spring程序员面临的配置噩梦中解放出来。MongoTemplate确实是工程师的救星,他们可以轻松地构建自己的类和交互,因为它具有很大的灵活性。结构可以是这样的:
1.创建一个将在应用程序级别运行的MongoClientFactory类,并给予一个MongoClient对象。您可以将其实现为Singleton或使用EnumSingleton(这是线程安全的)
1.创建一个数据访问基类,您可以从该基类继承每个域对象的数据访问对象)。基类可以实现一个方法来创建一个MongoTemplate对象,您可以使用特定于类的方法进行所有DB访问
1.每个域对象的每个数据访问类都可以实现基本方法,也可以在基类中实现这些方法

  1. Controller方法然后可以根据需要调用Data访问类中的方法。

相关问题