一、JDBC弊端
- 重復(fù)創(chuàng)建鏈接和釋放鏈接,造成資源浪費(fèi)。解決方式:使用連接池
- 出現(xiàn)硬編碼,體現(xiàn)在數(shù)據(jù)庫驅(qū)動(dòng),url、用戶名密碼、sql。解決方式:使用配置文件
- 結(jié)果獲取不方便。解決方式:把結(jié)果放到一個(gè)POJO中
二、Mybatis的介紹
MyBatis 本是apache的一個(gè)開源項(xiàng)目iBatis,2010年這個(gè)項(xiàng)目由apache software foundation 遷移到了google code,并且改名為MyBatis 。2013年11月遷移到Github。iBATIS一詞來源于“internet”和“abatis”的組合,是一個(gè)基于Java的持久層框架。iBATIS提供的持久層框架包括SQL Maps和Data Access Objects(DAOs)。當(dāng)前,最新版本是MyBatis 3.5.1 ,其發(fā)布時(shí)間是2019年4月8日。
MyBatis 是一款支持普通 SQL查詢,存儲(chǔ)過程和高級(jí)映射的優(yōu)秀持久層框架。MyBatis 消除了幾乎所有的JDBC代碼和參數(shù)的手工設(shè)置以及結(jié)果集的檢索。MyBatis 使用簡單的 XML或注解用于配置和原始映射,將接口和 Java 的POJOs(Plain Ordinary Java Objects,普通的 Java對(duì)象)映射成數(shù)據(jù)庫中的記錄。
每個(gè)MyBatis應(yīng)用程序主要都是使用SqlSessionFactory實(shí)例的,一個(gè)SqlSessionFactory實(shí)例可以通過SqlSessionFactoryBuilder獲得。SqlSessionFactoryBuilder可以從一個(gè)xml配置文件或者一個(gè)預(yù)定義的配置類的實(shí)例獲得。
用xml文件構(gòu)建SqlSessionFactory實(shí)例是非常簡單的事情。推薦在這個(gè)配置中使用類路徑資源(classpath resource),但你可以使用任何Reader實(shí)例,包括用文件路徑或file://開頭的url創(chuàng)建的實(shí)例。MyBatis有一個(gè)實(shí)用類----Resources,它有很多方法,可以方便地從類路徑及其它位置加載資源。
三、Mybatis架構(gòu)

- mybatis配置 SqlMapConfig.xml,此文件作為mybatis的全局配置文件,配置了mybatis的運(yùn)行環(huán)境等信息。mapper.xml文件即sql映射文件,文件中配置了操作數(shù)據(jù)庫的sql語句。此文件需要在SqlMapConfig.xml中加載。
- 通過mybatis環(huán)境等配置信息構(gòu)造SqlSessionFactory即會(huì)話工廠。
- 由會(huì)話工廠創(chuàng)建sqlSession即會(huì)話,操作數(shù)據(jù)庫需要通過sqlSession進(jìn)行。
- mybatis底層自定義了Executor執(zhí)行器接口操作數(shù)據(jù)庫,Executor接口有兩個(gè)實(shí)現(xiàn),一個(gè)是基本執(zhí)行器、一個(gè)是緩存執(zhí)行器。
- Mapped Statement也是mybatis一個(gè)底層封裝對(duì)象,它包裝了mybatis配置信息及sql映射信息等。mapper.xml文件中一個(gè)sql對(duì)應(yīng)一個(gè)Mapped Statement對(duì)象,sql的id即是Mapped statement的id。
- Mapped Statement對(duì)sql執(zhí)行輸入?yún)?shù)進(jìn)行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執(zhí)行sql前將輸入的java對(duì)象映射至sql中,輸入?yún)?shù)映射就是jdbc編程中對(duì)preparedStatement設(shè)置參數(shù)。
- 輸入映射(傳入的參數(shù))
支持的數(shù)據(jù)類型:
基本數(shù)據(jù)類型:基礎(chǔ)類型以及包裝類、String
POJO
Map
包裝的POJO:一個(gè)pojo中有pojo屬性
- Mapped Statement對(duì)sql執(zhí)行輸出結(jié)果進(jìn)行定義,包括HashMap、基本類型、pojo,Executor通過Mapped Statement在執(zhí)行sql后將輸出結(jié)果映射至java對(duì)象中,輸出結(jié)果映射過程相當(dāng)于jdbc編程中對(duì)結(jié)果的解析處理過程。
- 輸出映射(產(chǎn)生的結(jié)果類型)
基本數(shù)據(jù)類型:基礎(chǔ)類型以及包裝類、String
POJO
Map
List
四、MyBatis xml配置文件層次結(jié)構(gòu)

properties元素
properties是一個(gè)配置屬性的元素,讓開發(fā)者能在配置文件的上下文中使用它,MyBatis提供3種配置方式:
- property子元素。
- properties配置文件。
- SqlSessionFactoryBuilder使用Properties文件構(gòu)建。
property子元素
<property name="driver" value="com.mysql.jdbc.Driver"/>
properties配置文件
一般會(huì)使用一個(gè)單獨(dú)的properties配置文件來配置屬性值,以方便在多個(gè)配置文件中重復(fù)使用它們,也方便日后維護(hù)和隨時(shí)修改??梢酝ㄟ^${key}的形式,取出在配置文件中配置的值。
<configuration>
<!-- 引入配置文件 -->
<properties resource="datasource.properties"/>
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<!-- 使用配置文件中的屬性 -->
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
</dataSource>
</environment>
</environments>
</configuration>
SqlSessionFactoryBuilder使用Properties文件構(gòu)建
出于安全考慮,properties配置文件中的賬號(hào)密碼等元素可能是加密的,這個(gè)時(shí)候就需要對(duì)加密的元素進(jìn)行處理。
public static void func() throws Exception {
Properties properties = new Properties();
properties.load(Resources.getResourceAsStream("datasource.properties"));
// 對(duì)原賬號(hào)密碼解密
properties.setProperty("username", decode(properties.getProperty("username")));
properties.setProperty("password", decode(properties.getProperty("password")));
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// SqlSessionFactoryBuilder可以使用一個(gè)InputStream和一個(gè)Properties構(gòu)建SqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is, properties);
}
三種方式的優(yōu)先級(jí)
MyBatis支持的3種配置方式可能同時(shí)出現(xiàn),并且屬性還會(huì)重復(fù)配置,MyBatis將按照下面的順序來加載:
- 在properties元素體內(nèi)指定的屬性首先被讀取。
- 根據(jù) properties元素中的resource屬性讀取類路徑下屬性文件,或者根據(jù)url屬性指定的路徑讀取屬性文件,并覆蓋已讀取的同名屬性。
- 讀取作為build()方法參數(shù)傳遞的屬性,并覆蓋已讀取的同名屬性。
因此,通過build()方法參數(shù)傳遞的屬性具有最高優(yōu)先級(jí),resource/url屬性中指定的配置文件次之,最低優(yōu)先級(jí)的是 properties屬性中指定的屬性。因此,我們盡量不要使用混合的方式來定義配置,首選的方式是使用properties文件。
五、environments環(huán)境變量
配置環(huán)境可以注冊(cè)多個(gè)環(huán)境,每一個(gè)環(huán)境分為兩大部分:一個(gè)是數(shù)據(jù)庫源(dataSource)的配置,另外一個(gè)是數(shù)據(jù)庫事務(wù)(transactionManager)的配置。
<environments default="dev">
<environment id="dev">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
</dataSource>
</environment>
</environments>
- default:表示默認(rèn)使用哪個(gè)數(shù)據(jù)源
- id:表示數(shù)據(jù)源的名稱
- transactionManager的事務(wù)類型type一共有三種:JDBC,采用JDBC方式管理事務(wù),獨(dú)立編碼中我們常常使用;MANAGED,采用容器方式管理事務(wù),在JNDI數(shù)據(jù)源中常用;自定義,由使用者自定義數(shù)據(jù)庫事務(wù)管理辦法,適用于特殊應(yīng)用。
- property元素配置數(shù)據(jù)源的各類屬性
- dataSource的type屬性是提供我們對(duì)數(shù)據(jù)厙連接方式的配置:UNPOOLED(非連接池?cái)?shù)據(jù)庫)、POOLED(連接池?cái)?shù)據(jù)庫)、JNDI(JNDI數(shù)據(jù)源)、自定義數(shù)據(jù)源。
六、數(shù)據(jù)源
MyBatis內(nèi)部為我們提供了3種數(shù)據(jù)源的實(shí)現(xiàn)方式:
- UNPOOLED,使用org.apache.ibatis.datasource.unpooled.UnpooledDataSource實(shí)現(xiàn)。
- POOLED,使用org.apache.ibatis.datasource.pooled.PooledDataSource實(shí)現(xiàn)。
- JNDI,使用org.apache.ibatis.datasource.jndi.JndiDataSourceFactory實(shí)現(xiàn)。
七、數(shù)據(jù)庫事務(wù)
數(shù)據(jù)庫事務(wù)是交由SqlSession去控制的,我們可以通過SqlSession提交或者回滾。在大部分的工作環(huán)境下,我們都會(huì)使用 Spring框架來控制它。
八、Mybatis解決jdbc編程的問題
- 數(shù)據(jù)庫鏈接創(chuàng)建、釋放頻繁造成系統(tǒng)資源浪費(fèi)從而影響系統(tǒng)性能,如果使用數(shù)據(jù)庫鏈接池可解決此問題。
解決:在SqlMapConfig.xml中配置數(shù)據(jù)鏈接池,使用連接池管理數(shù)據(jù)庫鏈接。 - Sql語句寫在代碼中造成代碼不易維護(hù),實(shí)際應(yīng)用sql變化的可能較大,sql變動(dòng)需要改變java代碼。
解決:將Sql語句配置在XXXXmapper.xml文件中與java代碼分離。 - 向sql語句傳參數(shù)麻煩,因?yàn)閟ql語句的where條件不一定,可能多也可能少,占位符需要和參數(shù)一一對(duì)應(yīng)。
解決:Mybatis自動(dòng)將java對(duì)象映射至sql語句,通過statement中的parameterType定義輸入?yún)?shù)的類型。 - 對(duì)結(jié)果集解析麻煩,sql變化導(dǎo)致解析代碼變化,且解析前需要遍歷,如果能將數(shù)據(jù)庫記錄封裝成pojo對(duì)象解析比較方便。
解決:Mybatis自動(dòng)將sql執(zhí)行結(jié)果映射至java對(duì)象,通過statement中的resultType定義輸出結(jié)果的類型。