簡體   English   中英

Spring Data 的 MongoTemplate 和 MongoRepository 有什么區別?

[英]What's the difference between Spring Data's MongoTemplate and MongoRepository?

我需要編寫一個應用程序,通過它我可以使用 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/

你能告訴我什么是更方便和強大的使用嗎? mongoTemplateMongoRepository 兩者都同樣成熟,還是其中一個缺少比另一個更多的功能?

“方便”和“強大使用”在某種程度上是相互矛盾的目標。 存儲庫比模板方便得多,但后者當然可以讓您更精細地控制要執行的內容。

由於存儲庫編程模型可用於多個 Spring Data 模塊,您將在 Spring Data MongoDB 參考文檔的常規部分中找到更深入的文檔

TL; 博士

我們通常推薦以下方法:

  1. 從存儲庫摘要開始,只需使用查詢派生機制或手動定義的查詢聲明簡單的查詢。
  2. 對於更復雜的查詢,將手動實現的方法添加到存儲庫(如此處所述)。 對於實現,請使用MongoTemplate

細節

對於您的示例,這看起來像這樣:

  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 { }

通過這種方式,您基本上可以選擇:所有易於聲明的內容都進入UserRepository ,更好地手動實現的所有內容都進入CustomUserRepository 自定義選項記錄在此處

FWIW,關於多線程環境中的更新:

  • MongoTemplate提供了“原子”開箱即用的操作updateFirstupdateMultifindAndModifyupsert ...,允許您在單個操作中修改文檔。 這些方法使用的Update對象還允許您僅定位相關字段
  • MongoRepository只為您提供基本的 CRUD 操作findinsertsavedelete ,這些操作適用於包含所有字段的POJO。 這迫使您分幾個步驟更新文檔(1. find要更新的文檔,2. 從返回的 POJO 中修改相關字段,然后 3. 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操作命中數據庫最后。
(注意:即使我們按照評論中的建議使用Spring Data 的@Version注釋,也不會發生太大變化:其中一個save操作將拋出OptimisticLockingFailureException ,最終文檔仍將是上述文檔之一,僅更新一個字段而不是兩者。)

所以我會說MongoTemplate是一個更好的選擇,除非你有一個非常詳細的 POJO 模型或者出於某種原因需要MongoRepository的自定義查詢功能。

這個答案可能有點延遲,但我建議避免整個存儲庫路線。 您幾乎沒有獲得任何具有重大實用價值的實現方法。 為了使它工作,您會遇到 Java 配置廢話,您可能會花費數天和數周的時間,而無需在文檔中提供太多幫助。

相反,使用MongoTemplate路由並創建您自己的數據訪問層,從而使您擺脫 Spring 程序員面臨的配置噩夢。 MongoTemplate確實是工程師的救星,因為它們具有很大的靈活性,因此可以輕松地構建自己的類和交互。 結構可以是這樣的:

  1. 創建一個將在應用程序級別運行的MongoClientFactory類,並為您提供一個MongoClient對象。 您可以將其實現為 Singleton 或使用 Enum Singleton(這是線程安全的)
  2. 創建一個數據訪問基類,您可以從中繼承每個域對象的數據訪問對象)。 基類可以實現用於創建 MongoTemplate 對象的方法,您可以將其分類為特定方法可用於所有數據庫訪問
  3. 每個域對象的每個數據訪問類都可以實現基本方法,也可以在基類中實現它們
  4. 然后,控制器方法可以根據需要調用數據訪問類中的方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM