首先表達我的觀點,JPA必然是首選的。git
我的認爲僅僅討論二者使用起來有何區別,何者更加方便,不足以真正的比較這兩個框架。要評判出更加優秀的方案,我以爲能夠從軟件設計的角度來評判。我的對 mybatis 並不熟悉,但 JPA 規範和 springdata 的實現,設計理念絕對是超前的。軟件開發複雜性的一個解決手段是遵循 DDD(DDD 只是一種手段,但不是惟一手段),而我着重幾點來聊聊 JPA 的設計中是如何體現領域驅動設計思想的,拋磚引玉。redis
領域驅動設計中有兩個廣爲你們熟知的概念,entity(實體)和 value object(值對象)。entity 的特色是具備生命週期的,有標識的,而值對象是起到一個修飾的做用,其具備不可變性,無標識。在 JPA中 ,須要爲數據庫的實體類添加 @Entity 註解,相信你們也注意到了,這並非巧合。spring
@Entitysql
@Table(name = "t_order")mongodb
public class Order {數據庫
@Id緩存
private String oid;微信
@Embeddedmybatis
private CustomerVo customer;架構
@OneToMany(cascade = {CascadeType.ALL}, orphanRemoval = true, fetch = FetchType.LAZY, mappedBy = "order")
private List<OrderItem> orderItems;
}
如上述的代碼,Order 即是 DDD 中的實體,而 CustomerVo,OrderItem 則是值對象。程序設計者無需關心數據庫如何映射這些字段,由於在 DDD 中,須要作的工做是領域建模,而不是數據建模。實體和值對象的意義不在此展開討論,但經過此能夠初見端倪,JPA 的內涵毫不僅僅是一個 ORM 框架。
Repository 模式是領域驅動設計中另外一個經典的模式。在早期,咱們經常將數據訪問層命名爲:DAO,而在 SpringData JPA 中,其稱之爲 Repository(倉儲),這也不是巧合,而是設計者有意爲之。
熟悉 SpringData JPA 的朋友都知道當一個接口繼承 JpaRepository 接口以後便自動具有了 一系列經常使用的數據操做方法,findAll
, findOne
,save
等。
public interface OrderRepository extends JpaRepository<Order, String>{
}
那麼倉儲和DAO到底有什麼區別呢?這就要提到一些遺留問題,以及一些軟件設計方面的因素。在此次SpringForAll 的議題中我可以預想到有不少會強調 SpringData JPA 具備方即可擴展的 API,像下面這樣:
public interface OrderRepository extends JpaRepository<Order, String>{
findByOrderNoAndXxxx(String orderNo,Xxx xx);
@Transactional
@Modifying(clearAutomatically = true)
@Query("update t_order set order_status =?1 where id=?2")
int updateOrderStatusById(String orderStatus, String id);
}
但我要強調的是,這是 SpringData JPA 的妥協,其支持這一特性,並不表明其建議使用。由於這並不符合領域驅動設計的理念。注意對比,SpringData JPA 的設計理念是將 Repository 做爲數據倉庫,而不是一系列數據庫腳本的集合,findByOrderNoAndXxxx
方法能夠由下面一節要提到的JpaSpecificationExecutor
代替,而 updateOrderStatusById
方法則能夠由 findOne
+ save
代替,不要以爲這變得複雜了,試想一下真正的業務場景,修改操做通常不會只涉及一個字段的修改, findOne
+ save
能夠幫助你完成更加複雜業務操做,而沒必要關心咱們該如何編寫 SQL 語句,真正作到了面向領域開發,而不是面向數據庫 SQL 開發,面向對象的擁躉者也必然會以爲,這更加的 OO。
上面提到 SpringData JPA 能夠藉助 Specification 模式代替複雜的 findByOrderNoAndXxxx
一類 SQL 腳本的查詢。試想一下,業務不停在變,你怎麼知道未來的查詢會不會多一個條件 變成 findByOrderNoAndXxxxAndXxxxAndXxxx....
。SpringData JPA 爲了實現領域驅動設計中的 Specification 模式,提供了一些列的 Specification 接口,其中最經常使用的即是 :JpaSpecificationExecutor
public interface OrderRepository extends JpaRepository<Order,String>,JpaSpecificationExecutor<Order>{
}
使用 SpringData JPA 構建複雜查詢(join操做,彙集操做等等)都是依賴於 JpaSpecificationExecutor 構建的 Specification 。例子就不介紹,有點長。
請注意,上述代碼並非一個例子,在真正遵循 DDD 設計規範的系統中,OrderRepository 接口中就應該是乾乾淨淨的,沒有任何代碼,只須要繼承 JpaRepository (負責基礎CRUD)以及 JpaSpecificationExecutor (負責Specification 查詢)便可。固然, SpringData JPA 也提供了其餘一系列的接口,根據特定業務場景繼承便可。
爲了解決數據併發問題,JPA 中提供了 @Version
,通常在 Entity 中 添加一個 Long version
字段,配合 @Version
註解,SpringData JPA 也考慮到了這一點。這一點側面體現出,JPA 設計的理念和 SpringData 做爲一個工程解決方案的雙劍合璧,造就出了一個偉大的設計方案。
不少人青睞 Mybatis ,緣由是其提供了便利的 SQL 操做,自由度高,封裝性好……SpringData JPA對複雜 SQL 的支持很差,沒有實體關聯的兩個表要作 join ,的確要花很多功夫。但 SpringData JPA 並不把這個當作一個問題。爲何?由於現代微服務的架構,各個服務之間的數據庫是隔離的,跨越不少張表的 join 操做本就不該該交給單一的業務數據庫去完成。解決方案是:使用 elasticSearch作視圖查詢 或者 mongodb 一類的Nosql 去完成。問題本不是問題。
真正走進 JPA,真正走進 SpringData 會發現,咱們並非在解決一個數據庫查詢問題,並非在使用一個 ORM 框架,而是真正地在實踐領域驅動設計。
(再次補充:DDD 只是一種手段,但不是惟一手段)
lexburne 兄說的也很不錯了,不過我還想在補充2點,來消除你們對使用spring data jpa 的誤解
spring data jpa 的好處我相信你們都瞭解,就是開發速度很快,很方便,你們不肯意使用spring data jpa 的地方一般是由於sql 不是本身寫的,不可控,複雜查詢很差搞,那麼下面我要說的就是其實對於這種需求,spring data jpa 是徹底支持的!!
第一種方式:@query 註解指定nativeQuery,這樣就可使用原生sql查詢了,示例代碼來自官方文檔:
2.若是單靠sql搞不定怎麼辦?必需要寫邏輯怎麼辦?可使用官方文檔3.6.1 節:Customizing individual repositories 提供的功能去實現,先看官方文檔的代碼:
我來解釋下上面的代碼,若是搞不定的查詢方法,能夠自定義接口,例如CustomizedUserRepository ,和他的實現了類,而後在這個實現類裏用你本身喜歡的dao 框架,好比說mybatis ,jdbcTemplate ,都隨意,最後在用UserRepository 去繼承CustomizedUserRepository接口,就實現了和其餘dao 框架的組合使用!!
interface CustomizedUserRepository {
void someCustomMethod(User user);
}
class CustomizedUserRepositoryImplimplementsCustomizedUserRepository {
public void someCustomMethod(User user) {
// Your custom implementation
}
}
interface UserRepository extends CrudRepository<User, Long>, CustomizedUserRepository {
// Declare query methods here
}
public interface UserRepository extends JpaRepository<User, Long> {
@Query(value = "SELECT * FROM USERS WHERE EMAIL_ADDRESS = ?1", nativeQuery = true)
User findByEmailAddress(String emailAddress);
}
那麼下面我在總結1下,有了上面介紹的2種功能,你還在擔憂,使用spring data jpa 會有侷限麼,他只會加速你的開發速度,並容許你組合使用其餘框架,只有好處,沒有壞處。。
最後再說1點,我最近在看es ,而後看了下spring data es 的文檔,大概掃了1下,我發現,學會spring data 其中某1個系列之後,在看其餘的,我發現我都不用花時間學。。直接就能夠用,對就是這麼神奇~~
工做以來一直是使用 hibernate 和 mybatis,總結下來通常傳統公司、我的開發(可能只是我)喜歡用jpa,互聯網公司更青睞於 mybatis
緣由:,而mybatis 更加靈活。開發迭代模式決定的,傳統公司需求迭代速度慢,項目改動小,hibernate能夠幫他們作到一勞永逸;而互聯網公司追求快速迭代,需求快速變動,靈活的 mybatis 修改起來更加方便,並且通常每一次的改動不會帶來性能上的降低,hibernate常常由於添加關聯關係或者開發者不瞭解優化致使項目愈來愈糟糕(原本開始也是性能很好的)
一、mybatis官方文檔就說了他是一個半自動化的持久層框架,相對於全自動化的 hibernate 他更加的靈活、可控
二、mybatis 的學習成本低於 hibernate。hibernate 使用須要對他有深刻的理解,尤爲是緩存方面,做爲一個持久層框架,性能依然是第一位的。
hibernate 它有着三級緩存,一級緩存是默認開啓的,二級緩存須要手動開啓以及配置優化,三級緩存能夠整合業界流行的緩存技術 redis,ecache 等等一塊兒去實現
hibernate 使用中的優化點:
一、緩存的優化
二、關聯查詢的懶加載(在開發中,仍是不建議過多使用外鍵去關聯操做)
jpa(Java Persistence API) 與 hibernate 的關係:
Jpa是一種規範,hibernate 也是聽從他的規範的。
springDataJpa 是對 repository 的封裝,簡化了 repository 的操做
數據分析型的OLAP應用適合用MyBatis,事務處理型OLTP應用適合用JPA。
越是複雜的業務,越須要領域建模,建模用JPA實現最方便靈活。可是JPA想用好,門檻比較高,不懂DDD的話,就會淪爲增刪改查了。
複雜的查詢應該是經過CQRS模式,經過異步隊列創建合適查詢的視圖,經過視圖避免複雜的Join,而不是直接查詢領域模型。
從目前的趨勢來看OLAP交給NoSQL數據庫可能更合適
使用了一段時間jpa,而mybatis是以前一直在用的,不說區別是啥,由於有不少人比較這兩個框架了!
從國內開源的應用框架來看,國內使用jpa作orm的人仍是比較少,若是換成hibernate還會多一些,因此面臨的風險可能就是你會用,和你合做的人不必定會用,若是要多方協做,確定要考慮這個問題!
靈活性方面,jpa更靈活,包括基本的增刪改查、數據關係以及數據庫的切換上都比mybatis靈活,可是jpa門檻較高,另外就是更新數據須要先將數據查出來才能進行更新,數據量大的時候,jpa效率會低一些,這時候須要作一些額外的工做去處理!
如今結合Springboot有Springdata jpa給到,不少東西都簡化了,感興趣而且有能力能夠考慮在公司內部和圈子裏推廣!學習棧碼雲倉庫中有以前作的關於Springboot整合JPADemo:
https://gitee.com/learning_stack_database/learnstack.git
1.相對來講,jpa的學習成本比mybatis略高
2.公司業務需求頻繁變動致使表結構複雜,此處使用mybatis比jpa更靈活
3.就方言來說,通常公司選定數據庫後再變動微乎其微,因此此處方言的優點能夠忽略
添加小編微信,加入技術交流羣or招聘交流羣
QQ千人技術交流羣: 710566091 一塊兒學習一塊兒成長
學習棧公衆號,掃碼關注回覆獲取更多學習資料,點擊專題學習更多知識