${}是Properties文件中的變量佔位符,它能夠用於標籤屬性值和sql內部,屬於靜態文本替換,好比${driver}會被靜態替換爲com.mysql.jdbc.Driver。#{}是sql的參數佔位符,Mybatis會將sql中的#{}替換爲?號,在sql執行前會使用PreparedStatement的參數設置方法,按序給sql的?號佔位符設置參數值,好比ps.setInt(0, parameterValue),#{item.name}的取值方式爲使用反射從參數對象中獲取item對象的name屬性值,至關於param.getItem().getName()。java
還有不少其餘的標籤,<resultMap>、<parameterMap>、<sql>、<include>、<selectKey>,加上動態sql的9個標籤,trim|where|set|foreach|if|choose|when|otherwise|bind等,其中<sql>爲sql片斷標籤,經過<include>標籤引入sql片斷,<selectKey>爲不支持自增的主鍵生成策略標籤。mysql
Dao接口,就是人們常說的Mapper接口,接口的全限名,就是映射文件中的namespace的值,接口的方法名,就是映射文件中MappedStatement的id值,接口方法內的參數,就是傳遞給sql的參數。sql
Mapper接口是沒有實現類的,當調用接口方法時,接口全限名+方法名拼接字符串做爲key值,可惟必定位一個MappedStatement,舉例:com.mybatis3.mappers.StudentDao.findStudentById,能夠惟一找到namespace爲com.mybatis3.mappers.StudentDao下面id = findStudentById的MappedStatement。在Mybatis中,每個<select>、<insert>、<update>、<delete>標籤,都會被解析爲一個MappedStatement對象。數據庫
Dao接口裏的方法,是不能重載的,由於是全限名+方法名的保存和尋找策略。緩存
Dao接口的工做原理是JDK動態代理,Mybatis運行時會使用JDK動態代理爲Dao接口生成代理proxy對象,代理對象proxy會攔截接口方法,轉而執行MappedStatement所表明的sql,而後將sql執行結果返回。數據結構
Mybatis使用RowBounds對象進行分頁,它是針對ResultSet結果集執行的內存分頁,而非物理分頁,能夠在sql內直接書寫帶有物理分頁的參數來完成物理分頁功能,也可使用分頁插件來完成物理分頁。mybatis
分頁插件的基本原理是使用Mybatis提供的插件接口,實現自定義插件,在插件的攔截方法內攔截待執行的sql,而後重寫sql,根據dialect方言,添加對應的物理分頁語句和物理分頁參數。app
舉例:select * from student,攔截sql後重寫爲:select t.* from (select * from student)t limit 0,10ide
Mybatis僅能夠編寫針對ParameterHandler、ResultSetHandler、StatementHandler、Executor這4種接口的插件,Mybatis使用JDK的動態代理,爲須要攔截的接口生成代理對象以實現接口方法攔截功能,每當執行這4種接口對象的方法時,就會進入攔截方法,具體就是InvocationHandler的invoke()方法,固然,只會攔截那些你指定須要攔截的方法。工具
實現Mybatis的Interceptor接口並複寫intercept()方法,而後在給插件編寫註解,指定要攔截哪個接口的哪些方法便可,記住,別忘了在配置文件中配置你編寫的插件。
第一種是使用<resultMap>標籤,逐必定義列名和對象屬性名之間的映射關係。
第二種是使用sql列的別名功能,將列別名書寫爲對象屬性名,好比T_NAME AS NAME,對象屬性名通常是name,小寫,可是列名不區分大小寫,Mybatis會忽略列名大小寫,智能找到與之對應對象屬性名,你甚至能夠寫成T_NAME AS NaMe,Mybatis同樣能夠正常工做。
有了列名與屬性名的映射關係後,Mybatis經過反射建立對象,同時使用反射給對象的屬性逐一賦值並返回,那些找不到映射關係的屬性,是沒法完成賦值的。
能,Mybatis不只能夠執行一對1、一對多的關聯查詢,還能夠執行多對一,多對多的關聯查詢,多對一查詢,其實就是一對一查詢,只須要把selectOne()修改成selectList()便可;多對多查詢,其實就是一對多查詢,只須要把selectOne()修改成selectList()便可。
關聯對象查詢,有兩種實現方式,一種是單獨發送一個sql去查詢關聯對象,賦給主對象,而後返回主對象。另外一種是使用嵌套查詢,嵌套查詢的含義爲使用join查詢,一部分列是A對象的屬性值,另一部分列是關聯對象B的屬性值,好處是隻發一個sql查詢,就能夠把主對象和其關聯對象查出來。
那麼問題來了,join查詢出來100條記錄,如何肯定主對象是5個,而不是100個?其去重複的原理是<resultMap>標籤內的<id>子標籤,指定了惟一肯定一條記錄的id列,Mybatis根據<id>列值來完成100條記錄的去重複功能,<id>能夠有多個,表明了聯合主鍵的語意。
一樣主對象的關聯對象,也是根據這個原理去重複的,儘管通常狀況下,只有主對象會有重複記錄,關聯對象通常不會重複。
舉例:下面join查詢出來6條記錄,1、二列是Teacher對象列,第三列爲Student對象列,Mybatis去重複處理後,結果爲1個老師6個學生,而不是6個老師6個學生。
t_idt_names_id1teacher381teacher391teacher401teacher411teacher421teacher43
Mybatis僅支持association關聯對象和collection關聯集合對象的延遲加載,association指的就是一對一,collection指的就是一對多查詢。在Mybatis配置文件中,能夠配置是否啓用延遲加載lazyLoadingEnabled=true|false。
它的原理是,使用CGLIB建立目標對象的代理對象,當調用目標方法時,進入攔截器方法,好比調用a.getB().getName(),攔截器invoke()方法發現a.getB()是null值,那麼就會單獨發送事先保存好的查詢關聯B對象的sql,把B查詢上來,而後調用a.setB(b),因而a的對象b屬性就有值了,接着完成a.getB().getName()方法的調用。這就是延遲加載的基本原理。
固然了,不光是Mybatis,幾乎全部的包括Hibernate,支持延遲加載的原理都是同樣的。
不一樣的Xml映射文件,若是配置了namespace,那麼id能夠重複;若是沒有配置namespace,那麼id不能重複;畢竟namespace不是必須的,只是最佳實踐而已。
緣由就是namespace+id是做爲Map<String, MappedStatement>的key使用的,若是沒有namespace,就剩下id,那麼,id重複會致使數據互相覆蓋。有了namespace,天然id就能夠重複,namespace不一樣,namespace+id天然也就不一樣。
Mybatis有三種基本的Executor執行器,SimpleExecutor、ReuseExecutor、BatchExecutor。
SimpleExecutor:每執行一次update或select,就開啓一個Statement對象,用完馬上關閉Statement對象。
ReuseExecutor:執行update或select,以sql做爲key查找Statement對象,存在就使用,不存在就建立,用完後,不關閉Statement對象,而是放置於Map<String, Statement>內,供下一次使用。簡言之,就是重複使用Statement對象。
BatchExecutor:執行update(沒有select,JDBC批處理不支持select),將全部sql都添加到批處理中(addBatch()),等待統一執行(executeBatch()),它緩存了多個Statement對象,每一個Statement對象都是addBatch()完畢後,等待逐一執行executeBatch()批處理。與JDBC批處理相同。
做用範圍:Executor的這些特色,都嚴格限制在SqlSession生命週期範圍內。
在Mybatis配置文件中,能夠指定默認的ExecutorType執行器類型,也能夠手動給DefaultSqlSessionFactory的建立SqlSession的方法傳遞ExecutorType類型參數。
Mybatis能夠映射枚舉類,不單能夠映射枚舉類,Mybatis能夠映射任何對象到表的一列上。映射方式爲自定義一個TypeHandler,實現TypeHandler的setParameter()和getResult()接口方法。TypeHandler有兩個做用,一是完成從javaType至jdbcType的轉換,二是完成jdbcType至javaType的轉換,體現爲setParameter()和getResult()兩個方法,分別表明設置sql問號佔位符參數和獲取列查詢結果。
雖然Mybatis解析Xml映射文件是按照順序解析的,可是,被引用的B標籤依然能夠定義在任何地方,Mybatis均可以正確識別。
原理是,Mybatis解析A標籤,發現A標籤引用了B標籤,可是B標籤還沒有解析到,尚不存在,此時,Mybatis會將A標籤標記爲未解析狀態,而後繼續解析餘下的標籤,包含B標籤,待全部標籤解析完畢,Mybatis會從新解析那些被標記爲未解析的標籤,此時再解析A標籤時,B標籤已經存在,A標籤也就能夠正常解析完成了。
Mybatis將全部Xml配置信息都封裝到All-In-One重量級對象Configuration內部。在Xml映射文件中,<parameterMap>標籤會被解析爲ParameterMap對象,其每一個子元素會被解析爲ParameterMapping對象。<resultMap>標籤會被解析爲ResultMap對象,其每一個子元素會被解析爲ResultMapping對象。每個<select>、<insert>、<update>、<delete>標籤均會被解析爲MappedStatement對象,標籤內的sql會被解析爲BoundSql對象。
Hibernate屬於全自動ORM映射工具,使用Hibernate查詢關聯對象或者關聯集合對象時,能夠根據對象關係模型直接獲取,因此它是全自動的。而Mybatis在查詢關聯對象或關聯集合對象時,須要手動編寫sql來完成,因此,稱之爲半自動ORM映射工具。
Mybatis首先去緩存中查詢結果集,若是沒有則查詢數據庫,若是有則從緩存取出返回結果集就不走數據庫。Mybatis內部存儲緩存使用一個HashMap,key爲hashCode+sqlId+Sql語句。value爲從查詢出來映射生成的java對象
Mybatis的二級緩存即查詢緩存,它的做用域是一個mapper的namespace,即在同一個namespace中查詢sql能夠從緩存中獲取數據。二級緩存是能夠跨SqlSession的。