MyBatis還是JPA?終于有答案了
對于一個和數(shù)據(jù)庫打交道的程序員來說,很快會面臨著一個艱難的選擇。到底是選擇MyBatis還是JPA呢?
很多人說,技術(shù)選擇,都要根據(jù)需求來,這個沒錯。但是,除了需求,還有很重要的一個環(huán)節(jié),那就是隊友的水平。如果你選擇了一些比較高級的技術(shù),那么就是在給整個團隊埋坑。
JPA的抽象層次更高,代碼寫起來也更簡潔,但是它一點都不簡單。雖然經(jīng)過了多次的培訓(xùn),我呆過的幾個團隊,還是把它用的和屎一樣。
我扔掉了JPA
我仔細想了一下,有下面幾點原因,造成了JPA在很多團隊根本就玩不下去。
- JPA適合業(yè)務(wù)模型固定的場景,適合比較穩(wěn)定的需求。但是國內(nèi)這種朝三暮四的需求風(fēng)格,產(chǎn)品經(jīng)理這種傳話筒式的設(shè)計模式,造成了需求的泛濫和不確定。JPA在這種模式下就是渣。
- JPA的技術(shù)要求比較高。不要懷疑,你剛開始用起里可能覺得非常簡單。但隨著你的深入使用,你會發(fā)現(xiàn)這是一個災(zāi)難。里面的各種轉(zhuǎn)換和緩存,會把人繞暈。而大多數(shù)的快餐程序員是不想要了解這些的。
- 很多程序員很會寫SQL,所以很多SQL語句長的很胖,長的要命。業(yè)務(wù)混亂,多張表關(guān)聯(lián),我甚至見過上百張業(yè)務(wù)表關(guān)聯(lián)的復(fù)雜業(yè)務(wù)。DBA無奈之下,通常都會有sql審核。JPA搞sql審核?還是弱了一點。
所以,不是JPA不好,而是它不符合國情而已。想要在公司內(nèi)推行JPA,你需要給我一個穩(wěn)定的產(chǎn)品團隊、一個牛X的技術(shù)團隊才行。
所以,大多數(shù)公司寧可寫一堆重復(fù)的、亂七八糟的Mybaits代碼,也不會輕易嘗試JPA,這是符合邏輯的,符合事物發(fā)展規(guī)律的。
所以,我們下面的文章就是來討論MyBatis的,來看一下Mybaits到底要怎么寫才算優(yōu)雅。
MyBatis為什么不好用
優(yōu)秀的程序員都是很懶的。所以很多人不想設(shè)計實體的sql。JPA可以直接根據(jù)Java的實體代碼,生成sql的庫表,這在使用Mybatis的人來看,是非常羨慕的。
使用MyBatis,要倒著來。需要先設(shè)計庫表,然后根據(jù)庫表反向生成一堆Java代碼和配置文件。
這個代碼生成器,就是mybatis-generator。
但是,請注意。這個生成器生成的代碼,有四種模式?。。∵@就是最讓初學(xué)者難受的地方。如果你也是剛接觸MyBatis,強烈推薦只關(guān)注下面第一種模式。
- MyBatis3 這種模式就是我們常用的方式,會生成domain類、Example類、mapper映射文件等。它生成的信息比較啰嗦,內(nèi)容幾乎無法改動。對于項目中自己寫的sql,一般都采用手寫的方式再寫一份,而不是改動原來的文件。
- MyBatis3Simple 上面這種模式的簡易代碼生成模式,缺少一些東西,但很簡潔。對MyBatis沒有經(jīng)驗,不推薦使用它。
- MyBatis3DynamicSql 這是通過Builder模式實現(xiàn)的動態(tài)SQL特性,你還需要加入額外的jar包。加上它之后,其實和JPA是有點相似的。既然如此,那為何不直接使用JPA呢?所以這個DSQL雖然是默認的生成行為,但是非常不推薦。
- MyBatis3Kotlin 這個不廢話。就是生成Kotlin版的一些配置和代碼信息。
所以,下面僅僅介紹MyBatis3模式的代碼生成。
要使用它,需要在pom.xml里加入它的依賴。
<dependency> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-core</artifactId> <optional>true</optional> <scope>test</scope> <version>1.4.0</version> </dependency>
我個人喜歡使用Java代碼來操作代碼生成這個過程,所以下面就是生成代碼的代碼。
public class MBGTool {
public static void main(String[] args) throws Exception {
List<String> warnings = new ArrayList<>();
boolean overwrite = true;
InputStream configFile = MBGTool.class.getResourceAsStream("/generator/generatorConfig.xml");
ConfigurationParser cp = new ConfigurationParser(warnings);
Configuration config = cp.parseConfiguration(configFile);
DefaultShellCallback callback = new DefaultShellCallback(overwrite);
MyBatisGenerator myBatisGenerator = new MyBatisGenerator(config, callback, warnings);
myBatisGenerator.generate(null);
}
}
從代碼中,我們可以看到需要配置一個generatorConfig.xml文件,用來規(guī)定怎么生成代碼文件。
<!DOCTYPE generatorConfiguration PUBLIC
"-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="simple" targetRuntime="MyBatis3">
<jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/mbye"
userId="root"
password="root"
/>
<javaModelGenerator targetPackage="com.github.javarunfast.mbye.domain" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
<property name="trimStrings" value="true"/>
</javaModelGenerator>
<sqlMapGenerator targetPackage="com.github.javarunfast.mbye.mapper" targetProject="src/main/resources"/>
<javaClientGenerator type="XMLMAPPER" targetPackage="com.github.javarunfast.mbye.mapper" targetProject="src/main/java">
<property name="enableSubPackages" value="true"/>
</javaClientGenerator>
<table tableName="test"/>
</context>
</generatorConfiguration>
運行我們的MBGTool文件之后,就可以生成MyBatis的代碼了。
怎么寫代碼最優(yōu)雅
但是,我這里并不是要推薦你使用這種模式。因為,它生成了一大堆無用的文件。假如你的項目使用了sonar這樣的代碼質(zhì)量審查工具,你會發(fā)現(xiàn)很多飄紅的地方,還有那要命的覆蓋率問題。
怎么辦?
經(jīng)過我多年的摸索,我現(xiàn)在推薦一種非常好用的寫法。自從我采用了這種方式之后,就再也沒有換過。
第一、不需要代碼生成器了
數(shù)據(jù)表的設(shè)計,還有domain的書寫,全部靠手工。這樣我們的代碼,如果有必要,還可以遷移到JPA上去。這種模式還能順便學(xué)習(xí)一下Java里面的數(shù)據(jù)類型,是如何和SQL里的數(shù)據(jù)類型一一對應(yīng)的。在做表設(shè)計的時候,順便能夠了解一些背后的原理。
第二、不需要寫映射文件了
生成器生成的東西,確實是有一堆無用的邏輯。比如我的某個數(shù)據(jù)表,根本不需要提供查詢所有和刪除這種動作,它還是默認提供了。
在這種簡約模式下,我們直接手寫Mapper文件,然后只聲明所需要的接口方法就可以了。
@Mapper
public interface AccountBasicMapper {
@Insert("AccountBasicMapper/insert.sql")
void insert(@Param("r") AccountBasic record);
}
可以看到,里面有一個Insert注解,我們傳入了一個具體的domain,然后,就可以在AccountBasicMapper目錄下的insert.sql文件里,書寫具體的sql語句了。
sql語句樣例如下:
INSERT INTO account_basic( account_id, nick_name, password, sex, state, photo_url, created, modified, version )VALUES ( <@p name="r.accountId"/>, <@p name="r.nickName"/>, <@p name="r.password"/>, <@p name="r.sex"/>, <@p name="r.state"/>, <@p name="r.photoUrl"/>, <@p name="r.created"/>, <@p name="r.modified"/>, <@p name="r.version"/> )
那么這是什么語法呢?它又是如何知道是這樣配置的呢?這就需要引入MyBatis的腳本語言配置功能。在這里,我們使用的freemark的模版。
不要忘了加入它的依賴。
<dependency> <groupId>org.mybatis.scripting</groupId> <artifactId>mybatis-freemarker</artifactId> <version>1.2.2</version> </dependency>
然后,在yaml文件里做上相應(yīng)的配置就ok了。
mybatis:
check_config_location: false
scripting-language-driver:
freemarker:
template-file:
base-dir: mappers/
path-provider:
includes-package-path: false
separate-directory-per-mapper: false
這種方式的好處和壞處
我個人是非常喜歡這種模式的。因為它有下面幾個好處:
- 用什么寫什么,代碼量少,簡潔優(yōu)雅。
- SQL集中,不用分散在代碼里,xml里,或者注解里。方便DBA進行SQL審核。由于沒了xml的干擾,SQL反而更加簡潔了。
- 一個DAO方法一個sql文件,模式單一可控。
- MyBatis的功能優(yōu)勢可以全部發(fā)揮,無縫集成。
當(dāng)然,缺點也是顯而易見的。
- 即使變了個參數(shù),也要修改很多sql文件。
- 需要為每一個方法配一個sql文件,即使這是個很弱智的插入查詢方法。
不過,我并不認為這是個問題。每一個方法配備一個sql文件,代碼寫起來反而更加簡單了。當(dāng)出現(xiàn)問題的時候,也不用根據(jù)邏輯進行跟蹤定位到拼接后的SQL語句。我現(xiàn)在,只需要拿到對應(yīng)方法的SQL文件,就可以改吧改吧,直接在sql終端里執(zhí)行調(diào)試。這樣,sql優(yōu)化也變的簡單了。
當(dāng)然,一個人一個習(xí)慣。我個人喜歡這種模式,而且在我的團隊里推行這種模式,發(fā)現(xiàn)運行的也很好。另外,程序員為了少寫重復(fù)的sql代碼,在設(shè)計Dao接口的時候,反而更加認真了。
這可能是一個額外的收獲吧。
到此這篇關(guān)于MyBatis還是JPA?終于有答案了的文章就介紹到這了,更多相關(guān)MyBatis還是JPA內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Springboot集成Jasypt實現(xiàn)配置文件加密的方法
Jasypt是一個java庫,它允許開發(fā)員以最少的努力為他/她的項目添加基本的加密功能,并且不需要對加密工作原理有深入的了解,這篇文章主要介紹了Springboot集成Jasypt實現(xiàn)配置文件加密,需要的朋友可以參考下2023-04-04
Java數(shù)據(jù)結(jié)構(gòu)之有向圖的拓撲排序詳解
這篇文章主要為大家詳細介紹了Java數(shù)據(jù)結(jié)構(gòu)中有向圖的拓撲排序,文中的示例代碼講解詳細,具有一定的借鑒價值,感興趣的小伙伴可以了解一下2022-11-11
springboot使用hibernate validator校驗方式
hibernate validator提供了一套比較完善、便捷的驗證實現(xiàn)方式。下面小編給大家介紹下springboot使用hibernate validator校驗方式,感興趣的朋友一起看看吧2018-01-01
java數(shù)學(xué)工具類Math詳解(round方法)
這篇文章主要為大家詳細介紹了java數(shù)學(xué)工具類Math,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-08-08
關(guān)于Java整合RocketMQ實現(xiàn)生產(chǎn)消費詳解
這篇文章主要介紹了關(guān)于Java整合RocketMQ實現(xiàn)生產(chǎn)消費詳解,RocketMQ作為一款純java、分布式、隊列模型的開源消息中間件,支持事務(wù)消息、順序消息、批量消息、定時消息、消息回溯等,需要的朋友可以參考下2023-05-05

