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

时间:2013-06-09 11:04:35

标签: java spring mongodb spring-data spring-data-mongodb

我需要编写一个应用程序,我可以使用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更好地记录了MongoRepositorymongoTemplate。我指的是以下文档:

http://static.springsource.org/spring-data/data-mongodb/docs/current/reference/html/

你能告诉我什么更方便,更强大吗? MongoRepository或{{1}}?两者是否同样成熟,或者其中一个缺少更多的功能而不是另一个?

3 个答案:

答案 0 :(得分:112)

“方便”和“强大的使用”在某种程度上是相互矛盾的。存储库比模板更方便,但后者当然可以让您对执行的内容进行更细粒度的控制。

由于存储库编程模型可用于多个Spring Data模块,因此您可以在Spring Data MongoDB reference docs的常规部分中找到更深入的文档。

<强> TL; DR

我们通常建议采用以下方法:

  1. 从存储库摘要开始,只使用查询派生机制或手动定义的查询声明简单查询。
  2. 对于更复杂的查询,请将手动实现的方法添加到存储库(如此处所述)。对于实施,请使用MongoTemplate
  3. <强>详情

    对于您的示例,这看起来像这样:

    1. 定义自定义代码的界面:

      interface CustomUserRepository {
      
        List<User> yourCustomMethod();
      }
      
    2. 为此类添加一个实现,并遵循命名约定以确保我们可以找到该类。

      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
        }
      }
      
    3. 现在让您的基础存储库接口扩展自定义存储库接口,基础架构将自动使用您的自定义实现:

      interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository {
      
      }
      
    4. 通过这种方式,您基本上可以做出选择:易于声明的所有内容都会进入UserRepository,手动实施的所有内容都会进入CustomUserRepository。自定义选项记录在here

答案 1 :(得分:17)

这个答案可能有点延迟,但我建议避免使用整个存储库路径。你得到的实践方法很少,具有很大的实用价值。为了使它工作,你会遇到Java配置废话,你可以花费数天和数周的时间在文档中没有太多帮助。

相反,请使用MongoTemplate路由并创建自己的数据访问层,这样您就可以摆脱Spring程序员面临的配置噩梦。 MongoTemplate对于那些能够很好地设计自己的类和交互的工程师来说真的是救星,因为它具有很大的灵活性。结构可以是这样的:

  1. 创建一个将在应用程序级别运行的MongoClientFactory类,并为您提供一个MongoClient对象。您可以将其实现为Singleton或使用Enum Singleton(这是线程安全的)
  2. 创建一个数据访问基类,您可以从中继承每个域对象的数据访问对象。基类可以实现一个创建MongoTemplate对象的方法,您可以使用该类对特定方法进行所有数据库访问。
  3. 每个域对象的每个数据访问类都可以实现基本方法,或者您可以在基类
  4. 中实现它们
  5. 然后,Controller方法可以根据需要调用数据访问类中的方法。

答案 2 :(得分:7)

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

  • MongoTemplate提供开箱即用的updateFirstupdateMultifindAndModifyupsert ...方法,可让您修改文档在一次操作中。这些方法使用的Update对象还允许您仅定位相关字段。
  • MongoRepository仅为您提供基本的findinsertsavedelete操作,这些操作适用于包含所有字段的POJO。这会强制您分几步更新文档(find要更新的文档,修改返回的POJO中的相关字段,然后save它,或者手动定义您自己的更新查询@Query

在多线程环境中,例如具有多个REST端点的Java后端,单方法更新是可行的方法,以减少两个并发更新覆盖彼此更改的机会。

示例:给出如下文档:{ _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 },因为每个线程仅在仅更改指定字段时访问数据库。

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操作首先命中数据库。

所以我要说 MongoTemplate是一个更好的选择,除非您有一个非常详细的POJO模型或由于某种原因需要MongoRepository的自定义查询功能。