MyBatis功能架構設計
功能架構講解:
我們把Mybatis的功能架構分為三層:
(1)API接口層:提供給外部使用的接口API,開發人員通過這些本地API來操縱數據庫。接口層一接收到調用請求就會調用數據處理層來完成具體的數據處理。
(2)數據處理層:負責具體的SQL查找、SQL解析、SQL執行和執行結果映射處理等。它主要的目的是根據調用的請求完成一次數據庫操作。
(3)基礎支撐層:負責最基礎的功能支撐,包括連接管理、事務管理、配置加載和緩存處理,這些都是共用的東西,將他們抽取出來作為最基礎的組件。為上層的數據處理層提供最基礎的支撐。
框架架構
MyBatis的初始化,會讀取mybatis-config.xml配置文件,解析構造成Configuration類。
(1)加載配置:配置來源於兩個地方,一處是配置文件,一處是Java代碼的注解,將SQL的配置信息加載成為一個個MappedStatement對象(包括了傳入參數映射配置、執行的SQL語句、結果映射配置),存儲在內存中。
(2)SQL解析:當API接口層接收到調用請求時,會接收到傳入SQL的ID和傳入對象(可以是Map、JavaBean或者基本數據類型),Mybatis會根據SQL的ID找到對應的MappedStatement,然后根據傳入參數對象對MappedStatement進行解析,解析后可以得到最終要執行的SQL語句和參數。
(3)SQL執行:將最終得到的SQL和參數拿到數據庫進行執行,得到操作數據庫的結果。
(4)結果映射:將操作數據庫的結果按照映射的配置進行轉換,可以轉換成HashMap、JavaBean或者基本數據類型,並將最終結果返回。
MyBatis核心類
1、SqlSessionFactoryBuilder
每一個MyBatis的應用程序的入口是SqlSessionFactoryBuilder。
它的作用是通過XML配置文件創建Configuration對象(當然也可以在程序中自行創建),然后通過build方法創建SqlSessionFactory對象。沒有必要每次訪問Mybatis就創建一次SqlSessionFactoryBuilder,通常的做法是創建一個全局的對象就可以了。示例程序如下:
private static SqlSessionFactoryBuilder sqlSessionFactoryBuilder; private static SqlSessionFactory sqlSessionFactory; private static void init() throws IOException { String resource = "mybatis-config.xml"; Reader reader = Resources.getResourceAsReader(resource); sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); sqlSessionFactory = sqlSessionFactoryBuilder.build(reader); }
org.apache.ibatis.session.Configuration 是mybatis初始化的核心。
mybatis-config.xml中的配置,最后會解析xml成Configuration這個類。
SqlSessionFactoryBuilder根據傳入的數據流(XML)生成Configuration對象,然后根據Configuration對象創建默認的SqlSessionFactory實例。
2、SqlSessionFactory對象由SqlSessionFactoryBuilder創建:
它的主要功能是創建SqlSession對象,和SqlSessionFactoryBuilder對象一樣,沒有必要每次訪問Mybatis就創建一次SqlSessionFactory,通常的做法是創建一個全局的對象就可以了。SqlSessionFactory對象一個必要的屬性是Configuration對象,它是保存Mybatis全局配置的一個配置對象,通常由SqlSessionFactoryBuilder從XML配置文件創建。這里給出一個簡單的示例:
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <!-- 配置別名 --> <typeAliases> <typeAlias type="org.iMybatis.abc.dao.UserDao" alias="UserDao" /> <typeAlias type="org.iMybatis.abc.dto.UserDto" alias="UserDto" /> </typeAliases> <!-- 配置環境變量 --> <environments default="development"> <environment id="development"> <transactionManager type="JDBC" /> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://127.0.0.1:3306/iMybatis?characterEncoding=GBK" /> <property name="username" value="iMybatis" /> <property name="password" value="iMybatis" /> </dataSource> </environment> </environments> <!-- 配置mappers --> <mappers> <mapper resource="org/iMybatis/abc/dao/UserDao.xml" /> </mappers> </configuration>
3.SqlSession
SqlSession對象的主要功能是完成一次數據庫的訪問和結果的映射,它類似於數據庫的session概念,由於不是線程安全的,所以SqlSession對象的作用域需限制方法內。SqlSession的默認實現類是DefaultSqlSession,它有兩個必須配置的屬性:Configuration和Executor。Configuration前文已經描述這里不再多說。SqlSession對數據庫的操作都是通過Executor來完成的。
SqlSession :默認創建DefaultSqlSession 並且開啟一級緩存,創建執行器 、賦值。
SqlSession有一個重要的方法getMapper,顧名思義,這個方式是用來獲取Mapper對象的。什么是Mapper對象?根據Mybatis的官方手冊,應用程序除了要初始並啟動Mybatis之外,還需要定義一些接口,接口里定義訪問數據庫的方法,存放接口的包路徑下需要放置同名的XML配置文件。
SqlSession的getMapper方法是聯系應用程序和Mybatis紐帶,應用程序訪問getMapper時,Mybatis會根據傳入的接口類型和對應的XML配置文件生成一個代理對象,這個代理對象就叫Mapper對象。應用程序獲得Mapper對象后,就應該通過這個Mapper對象來訪問Mybatis的SqlSession對象,這樣就達到里插入到Mybatis流程的目的。
SqlSession session= sqlSessionFactory.openSession(); UserDao userDao = session.getMapper(UserDao.class); UserDto user = new UserDto(); user.setUsername("iMybatis"); List<UserDto> users = userDao.queryUsers(user); public interface UserDao { public List<UserDto> queryUsers(UserDto user) throws Exception; } <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.iMybatis.abc.dao.UserDao"> <select id="queryUsers" parameterType="UserDto" resultType="UserDto" useCache="false"> <![CDATA[ select * from t_user t where t.username = #{username} ]]> </select> </mapper>
一級緩存:第一次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,如果沒有,從數據庫查詢用戶信息。得到用戶信息,將用戶信息存儲到一級緩存中。 如果中間sqlSession去執行commit操作(執行插入、更新、刪除),則會清空SqlSession中的一級緩存,這樣做的目的為了讓緩存中存儲的是最新的信息,避免臟讀。第二次發起查詢用戶id為1的用戶信息,先去找緩存中是否有id為1的用戶信息,緩存中有,直接從緩存中獲取用戶信息。
二級緩存:原理和一級緩存原理一樣,第一次查詢,會將數據放入緩存中,然后第二次查詢則會直接去緩存中取。但是一級緩存是基於 sqlSession 的,而 二級緩存是基於 mapper文件的namespace的,也就是說多個sqlSession可以共享一個mapper中的二級緩存區域,並且如果兩個mapper的namespace相同,即使是兩個mapper,那么這兩個mapper中執行sql查詢到的數據也將存在相同的二級緩存區域中。
二級緩存需要我們手動開啟,首先在全局配置文件 mybatis-configuration.xml 文件中加入如下代碼:
<!--開啟二級緩存 --> <settings> <setting name="cacheEnabled" value="true"/> </settings>
其次在 UserMapper.xml 文件中開啟緩存
<!-- 開啟二級緩存 --> <cache></cache>
我們可以看到 mapper.xml 文件中就這么一個空標簽<cache/>,其實這里可以配置<cache type="org.apache.ibatis.cache.impl.PerpetualCache"/>,PerpetualCache這個類是mybatis默認實現緩存功能的類。我們不寫type就使用mybatis默認的緩存,也可以去實現 Cache 接口來自定義緩存。
開啟了二級緩存后,還需要將要緩存的pojo實現Serializable接口,為了將緩存數據取出執行反序列化操作,因為二級緩存數據存儲介質多種多樣,不一定只存在內存中,有可能存在硬盤中,如果我們要再取這個緩存的話,就需要反序列化了。
4、Executor
Executor對象在創建Configuration對象的時候創建,並且緩存在Configuration對象里。Executor對象的主要功能是調用StatementHandler訪問數據庫,並將查詢結果存入緩存中(如果配置了緩存的話)。
5、StatementHandler
StatementHandler是真正訪問數據庫的地方,並調用ResultSetHandler處理查詢結果。
6、ResultSetHandler
處理查詢結果。
MyBatis成員層次&職責
1.SqlSession:作為MyBatis工作的主要頂層API,表示和數據庫交互的會話,完成必要數據庫增刪改查功能
2.Executor:MyBatis執行器,是MyBatis 調度的核心,負責SQL語句的生成和查詢緩存的維護
3.StatementHandler:封裝了JDBC Statement操作,負責對JDBCstatement的操作,如設置參數、將Statement結果集轉換成List集合。
4.ParameterHandler:負責對用戶傳遞的參數轉換成JDBC Statement 所需要的參數
5.ResultSetHandler:負責將JDBC返回的ResultSet結果集對象轉換成List類型的集合;
6.TypeHandler:負責java數據類型和jdbc數據類型之間的映射和轉換
7.MappedStatement:它保存映射器的一個節點(select|insert|delete|update),包括配置的SQL,SQL的id、緩存信息、resultMap、parameterType、resultType等重要配置內容。
8.SqlSource:負責根據用戶傳遞的parameterObject,動態地生成SQL語句,將信息封裝到BoundSql對象中,並返回
9.BoundSql:表示動態生成的SQL語句以及相應的參數信息
10.Configuration:MyBatis所有的配置信息都維持在Configuration對象之中