[英]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/
你能告訴我什么是更方便和強大的使用嗎? mongoTemplate
或MongoRepository
? 兩者都同樣成熟,還是其中一個缺少比另一個更多的功能?
“方便”和“強大使用”在某種程度上是相互矛盾的目標。 存儲庫比模板方便得多,但后者當然可以讓您更精細地控制要執行的內容。
由於存儲庫編程模型可用於多個 Spring Data 模塊,您將在 Spring Data MongoDB 參考文檔的常規部分中找到更深入的文檔。
TL; 博士
我們通常推薦以下方法:
MongoTemplate
。細節
對於您的示例,這看起來像這樣:
為您的自定義代碼定義一個接口:
interface CustomUserRepository { List<User> yourCustomMethod(); }
為該類添加一個實現並遵循命名約定以確保我們可以找到該類。
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 } }
現在讓您的基本存儲庫接口擴展自定義接口,基礎架構將自動使用您的自定義實現:
interface UserRepository extends CrudRepository<User, Long>, CustomUserRepository { }
通過這種方式,您基本上可以選擇:所有易於聲明的內容都進入UserRepository
,更好地手動實現的所有內容都進入CustomUserRepository
。 自定義選項記錄在此處。
FWIW,關於多線程環境中的更新:
MongoTemplate
提供了“原子”開箱即用的操作updateFirst
、 updateMulti
、 findAndModify
、 upsert
...,允許您在單個操作中修改文檔。 這些方法使用的Update
對象還允許您僅定位相關字段。MongoRepository
只為您提供基本的 CRUD 操作find
、 insert
、 save
、 delete
,這些操作適用於包含所有字段的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
確實是工程師的救星,因為它們具有很大的靈活性,因此可以輕松地構建自己的類和交互。 結構可以是這樣的:
MongoClientFactory
類,並為您提供一個MongoClient
對象。 您可以將其實現為 Singleton 或使用 Enum Singleton(這是線程安全的)
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.