聲明:本人通過(guò)《深入淺出MyBatis技術(shù)原理與實(shí)戰(zhàn)》來(lái)完成學(xué)習(xí)并總結(jié)如文.
Hibernate的相關(guān)缺點(diǎn)
1. 全表映射帶來(lái)的帶來(lái)的不便,更新要發(fā)送所有字段
2. 無(wú)法根據(jù)不同條件組裝SQL
3. 對(duì)多表關(guān)聯(lián)和復(fù)雜SQL查詢支持較差七兜,需要自己寫SQL抡草,返回后需要自己將數(shù)據(jù)組裝成POJO
4. 不能有效支持存儲(chǔ)過(guò)程
5. 性能差,無(wú)法做到SQL優(yōu)化
# POJO:Plain Ordinary Java Objecdt數(shù)據(jù)庫(kù)的表和簡(jiǎn)單JAVA對(duì)象的映射關(guān)系模型
mybatis
簡(jiǎn)單介紹:
mybatis是一個(gè)基于JAVA的持久層框架。與Hibernate的不同是:除了提供映射文件,還需要提供SQL語(yǔ)句阴幌。mybatis提供的映射文件主要包含以下三個(gè)部分:
- SQL
- 映射規(guī)則
- POJO
mybatis的核心組件:
- SqlSessionFactoryBuilder(構(gòu)造器):根據(jù)配置信息或代碼來(lái)生成SqlSessionFactory(工廠接口)
- 實(shí)現(xiàn)方式:
String resource = "mybatis-config.xml";
InputStream inputStream = Resource.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = null;
sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputstream);
- SqlSessionFactory:打開SqlSession(會(huì)話)
- 實(shí)現(xiàn)方式:
SqlSession sqlSession = null;
try{
sqlSesssion = sqlSessionFactory.openSesson();
//And code you need
sqlSession.commit();
}catch(Exception e){
e.printStackTrace();
}finally{
if(sqlSession != null){
sqlSession.close();
}
}
- SqlSession:一個(gè)發(fā)送SQL去執(zhí)行得到返回結(jié)果,并且獲取Mapper的接口
- 類似于前臺(tái)的一個(gè)作用卷中,我們把信息(功能矛双、參數(shù))交給前臺(tái)(Session),然后前臺(tái)返回我們需要的結(jié)果(Result)仓坞。它類似于JDBC里的Connection背零,當(dāng)我們完成操作后腰吟,需要顯示關(guān)閉它
- MyBatis中的SqlSession接口有兩種:
- DefaultSqlSession
- SqlSessionManager
- SQL Mapper:由一個(gè)Java接口和XML文件(或注解)構(gòu)成无埃,需要給出對(duì)應(yīng)的SQL和映射規(guī)則。負(fù)責(zé)發(fā)送SQL去執(zhí)行毛雇,并返回結(jié)果嫉称。
簡(jiǎn)單實(shí)現(xiàn)過(guò)程:
- 創(chuàng)建SqlSessionFactory
- 形象化的說(shuō)法通過(guò)一個(gè)工廠建造工具來(lái)建造一個(gè)工廠,這個(gè)工具就是上面說(shuō)的SqlSessionFactoryBuilder
- 有兩種建造方式:一種通過(guò)XML灵疮,一種通過(guò)JAVA代碼织阅,mybatis-config.xml代碼的配置,不做贅述震捣,玩家可以自己去搜索
- 通過(guò)SqlSessionFactory提供一個(gè)SqlSession
打開Session的一般方式正如上文所說(shuō)荔棉,而關(guān)于Session的具體用途主要有一下兩種:
- 獲取映射器闹炉,讓映射器通過(guò)命名空間和方法名稱找到對(duì)應(yīng)的SQL,發(fā)送給數(shù)據(jù)執(zhí)行并返回結(jié)果润樱。
- 直接通過(guò)命名信息去執(zhí)行SQL返回結(jié)果渣触,在SqlSession層可以通過(guò)update、insert壹若、select嗅钻、delete等方法,帶上SQL的id來(lái)操作在XML中配置好的SQL店展;也支持事務(wù)养篓,通過(guò)commit、rollback方法提交或者回滾事務(wù)赂蕴。
- 通過(guò)Mapper來(lái)映射數(shù)據(jù)庫(kù)項(xiàng)和Java對(duì)象柳弄,也就是所謂的映射器(映射器是Mybatis的核心內(nèi)容)
映射器主要是由Java接口和XML文件共同組成,它(映射器)主要有這樣幾個(gè)功能:
- 定義參數(shù)類型
- 描述緩存
- 描述SQL語(yǔ)句
- 定義查詢結(jié)果和POJO的映射關(guān)系
關(guān)于映射器的實(shí)現(xiàn)睡腿,主要也有兩種方式:
- XML文件方式:在mybatis-config.xml文件中通過(guò)如下語(yǔ)句描述了一個(gè)xml
<mappers> <mapper resource = "com/blaze/mybatis_try/mapper/Mapper.xml/> </mapper>
它是用來(lái)生成Mapper的语御。
- 代碼方式:主要是通過(guò)在Configuration里面注冊(cè)Mapper接口,并且寫入Java注解席怪。(關(guān)于這種方式应闯,各位同學(xué)可以自行搜索了解)
關(guān)于映射器實(shí)現(xiàn)方式的選擇,原書作者給了如下建議:
強(qiáng)烈建議選擇XML的方式實(shí)現(xiàn)挂捻,理由如下:
- SQL很復(fù)雜條件很多的情況下碉纺,寫在Java文件里可讀性較差,增加維護(hù)成本
- 功能不對(duì)等刻撒,Java注解是受限的而且功能有限骨田,但是Mybatis的Mapper內(nèi)容相當(dāng)多而且復(fù)雜,并且在功能上非常強(qiáng)大声怔,使用Java注解的方式态贤,對(duì)Mybatis的靈活性和功能都會(huì)有所損耗。而選擇XML實(shí)現(xiàn)方式醋火,可以帶來(lái)更為靈活的空間悠汽,體驗(yàn)Mybatis功能的強(qiáng)大和靈活。
核心組件的生命周期
理解生命周期的理由:如果不正確理解Mybatis組件的生命周期可能帶來(lái)很嚴(yán)重的并發(fā)問題芥驳,影響對(duì)Mybatis應(yīng)用的正確性和高性能柿冲。
- SqlSessionFactoryBuilder
SqlSessionFactoryBuilder的作用就是通過(guò)XML或者Java代碼來(lái)建造一個(gè)工廠(SqlSessionFactory),并且可以通過(guò)它建造多個(gè)這樣的工廠兆旬。一旦完成建造工廠的任務(wù)假抄,我們就應(yīng)該廢棄它,回收空間。所以它的生命周期只存在方法局部宿饱,完成工廠的建造即結(jié)束熏瞄。
- SqlSessionFactory
SqlSessionFactory的作用就是創(chuàng)建會(huì)話(SqlSession),相當(dāng)于JDBC的Connection連接谬以。每當(dāng)我們需要訪問數(shù)據(jù)庫(kù)時(shí)巴刻,就要通過(guò)SqlSessionFactory創(chuàng)建會(huì)話,所以SqlSessionFactory的生命周期應(yīng)該是整個(gè)Mybatis的生命周期蛉签。但是如果打開過(guò)多的SqlSession胡陪,就相當(dāng)于JDBC創(chuàng)建了過(guò)多的Connection,那么連接資源就會(huì)很快被耗盡碍舍,所以對(duì)于每一個(gè)數(shù)據(jù)庫(kù)柠座,只對(duì)應(yīng)一個(gè)SqlSessionFactory,以此來(lái)管理數(shù)據(jù)資源的分配片橡,防止連接資源被過(guò)度消耗妈经。
- SqlSession
SqlSession相當(dāng)于JDBC的connnection,生命周期應(yīng)該是在請(qǐng)求數(shù)據(jù)庫(kù)處理事務(wù)的過(guò)程中捧书,它存活于一個(gè)應(yīng)用的請(qǐng)求和操作吹泡,可以執(zhí)行多個(gè)SQL,保證事務(wù)的一致性经瓷。此外爆哑,它還是個(gè)線程不安全的對(duì)象,在多線程中應(yīng)當(dāng)注意數(shù)據(jù)庫(kù)的隔離級(jí)別和數(shù)據(jù)庫(kù)鎖等高級(jí)特性舆吮。并且當(dāng)SqlSession完成自身工作時(shí)需要及時(shí)關(guān)閉揭朝,以防止數(shù)據(jù)庫(kù)連接池的活動(dòng)資源減少,影響系統(tǒng)性能色冀。
- Mapper
Mapper是一個(gè)接口潭袱,沒有任何實(shí)現(xiàn)類,作用是發(fā)送SQL锋恬,返回所需結(jié)果屯换。所以它的生命周期應(yīng)該在一個(gè)SqlSession事務(wù)方法之內(nèi),是一個(gè)方法級(jí)別的東西与学,一旦完成一個(gè)事務(wù)的操作彤悔,即可廢棄。
配置
# Mybatis的配置文件對(duì)整個(gè)Mybatis體系有著很重要的作用癣防,而且具有規(guī)定的層次蜗巧,這些層次是不能隨意點(diǎn)到順序的掌眠,顛倒順序會(huì)導(dǎo)致Mybatis在解析XML時(shí)出現(xiàn)異常蕾盯。
Mybatis配置文件層次結(jié)構(gòu)
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--配置-->
<properties/><!--屬性-->
<setting/><!--設(shè)置-->
<typeAliases/><!--類型別名-->
<typeHanlders/><!--類型處理器-->
<objectFactory/><!--對(duì)象工廠-->
<plugins/><!--插件-->
<environments><!--配置環(huán)境-->
<environment><!--環(huán)境變量-->
<transactionManager/><!--事務(wù)管理器-->
<dataSource/><!--數(shù)據(jù)源-->
</environment>
</environments>
<databaseIdProvider/><!--數(shù)據(jù)庫(kù)廠商標(biāo)識(shí)-->
<mapper/><!--映射器-->
</configuration>
properties元素
Mybatis提供三種配置方式:
- property子元素
- 首先在屬性標(biāo)簽中進(jìn)行配置:
<properties>
<property name="driver" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
</properties>
2. 然后可以再dataSource中使用配置好的屬性值,例如:
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
</dataSource>
- properties配置文件
- 首先寫properties配置文件:
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mybatis
2.再mybatis-config.xml中進(jìn)行導(dǎo)入:
<properties resource="jdbc.properties"/>
-
程序參數(shù)傳遞
- 使用理由:
實(shí)際工作中,系統(tǒng)是由運(yùn)維人員配置级遭,生產(chǎn)數(shù)據(jù)庫(kù)的用戶密碼對(duì)于開發(fā)者而言是保密的望拖,為了系統(tǒng)的安全,運(yùn)維人員要求對(duì)配置文件中的數(shù)據(jù)庫(kù)用戶和密碼進(jìn)行加密挫鸽,這樣我們的配置文件中往往配置的事加密過(guò)后的數(shù)據(jù)庫(kù)信息说敏,這個(gè)時(shí)候只能用編碼的方式來(lái)傳遞我們所需要的數(shù)據(jù)庫(kù)信息。
- 假設(shè)jdbc.properties的username和password兩個(gè)屬性使用了加密的字符串丢郊,首先需要在生成SqlSessionFactory之前盔沫,將所需信息轉(zhuǎn)換為明文,接下來(lái)使用系統(tǒng)提供的decode(str)方法
InputStream cfgStream = null; Reader cfgReader = null; InputStream proStream = null; Reader proReader = null; Properties properties = null; try{ //讀入配置文件流 cfgStream = Resources.gerResourceAsStream("mybatis-confg.xml"); cfgReader = new InputStreamReader(cfgStream); //讀入屬性文件 proStream = Resources.getResourceAsStream(jdbc.properties); proReader = new InputStreamReader(proStream); properties = new Properties(); properties.load(proReader); //解密為明文 properties.setProperty("username",decode(properties.getProperty("username"))); properties.setProperty("password",decode(properties.getProperty("password"))); }
作者建議:
注意點(diǎn):當(dāng)這三種方式同時(shí)應(yīng)用在一次配置中時(shí)枫匾,第一種方式下的配置信息首先被讀取出來(lái)架诞,然后再通過(guò)第二種方式讀取配置信息,并且覆蓋已經(jīng)被讀取出的同名屬性干茉,最后才對(duì)使用第三種方式的配置信息進(jìn)行讀取谴忧,并繼續(xù)產(chǎn)生覆蓋。所以通過(guò)第三種方式創(chuàng)建的配置信息具有最高優(yōu)先級(jí)角虫。
在實(shí)際的操作中沾谓,主要注意以下2點(diǎn):
- 不要使用混合的方式來(lái)對(duì)配置信息進(jìn)行聲明
- 首選第一種方式
如果我們需要對(duì)其進(jìn)行加密或者其他加工以滿足特殊的要求,建議使用第三種方式戳鹅【唬可以使配置都來(lái)自于同一個(gè)配置文件,不容易產(chǎn)生沒有必要的歧義枫虏,同時(shí)方便管理
設(shè)置(settting)
一般情況下我們都不需要去配置它辣恋,或者只需要配置少數(shù)幾項(xiàng),由于表格過(guò)于龐大模软,還請(qǐng)讀者自己動(dòng)手去查閱mybatis配置文件相關(guān)設(shè)置配置信息伟骨。