mybatis3.4.6 原始碼分析
阿新 • • 發佈:2018-12-20
ORM(來自baidu): 物件關係對映(英語:(Object Relational Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現面向物件程式語言裡不同型別系統的資料之間的轉換
自我梳理了一下mybatis,歡迎大神批評指正,交流學習,感謝!
常用使用說明
- 使用mybatis整合pom配置 使用我的練習專案;第一次自己搭maven 可以在一個maven工程裡放子工程,這個方式還挺好的;兩個子專案可以共用父專案的pom配置
<dependencies> <!-- mysql --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.13</version> </dependency> <!-- mybatis --> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.4.6</version> </dependency> <!-- log4j --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>${log4j2.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>${log4j2.version}</version> </dependency> <!-- mybatis會用到 start --> <dependency> <groupId>org.javassist</groupId> <artifactId>javassist</artifactId> <version>3.21.0-GA</version> </dependency> <!-- https://mvnrepository.com/artifact/ognl/ognl --> <dependency> <groupId>ognl</groupId> <artifactId>ognl</artifactId> <version>2.7.3</version> </dependency> <!-- mybatis會用到 end --> <!-- mybatis 分頁外掛 --> <!-- https://mvnrepository.com/artifact/com.github.pagehelper/pagehelper --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.1.7</version> </dependency> </dependencies>
- 使用generator外掛使用 pom配置
<build> <plugins> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.7</version> <configuration> <!--允許移動生成的檔案--> <verbose>true</verbose> <!--允許覆蓋生成的檔案--> <overwrite>true</overwrite> <configurationFile>src/main/resources/config/generatorConfig.xml</configurationFile> </configuration> </plugin> </plugins> </build>
generator.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"> <!-- 注意這個外掛是增量向檔案中新增,會重複 --> <generatorConfiguration> <!-- 引入配置檔案 <properties resource="jdbc.properties"/> --> <!--資料庫驅動路徑--> <classPathEntry location="D:\TSBrowserDownloads\maven\mavenSource\mysql\mysql-connector-java\8.0.13\mysql-connector-java-8.0.13.jar" /> <context id="DB2Tables" targetRuntime="MyBatis3"> <commentGenerator> <property name="suppressAllComments" value="true"/><!-- 是否取消註釋 --> <property name="suppressDate" value="true" /> <!-- 是否生成註釋代時間戳--> </commentGenerator> <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/zhaowd?serverTimezone=GMT" userId="root" password="12345"> </jdbcConnection> <!-- 型別轉換 --> <javaTypeResolver> <!-- 是否使用bigDecimal, false可自動轉化以下型別(Long, Integer, Short, etc.) --> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成實體類的包名和位置 注意targetProject的值為實體類放在工程中具體位置的相對路徑,--> <javaModelGenerator targetPackage="zhaowd.source" targetProject="src/main/java"> <!-- 是否在當前路徑下新加一層schema,eg:fase路徑com.oop.eksp.user.model, true:com.oop.eksp.user.model.[schemaName] --> <property name="enableSubPackages" value="true"/> <!-- 是否針對string型別的欄位在set的時候進行trim呼叫 --> <property name="trimStrings" value="true"/> </javaModelGenerator> <!--XML對映檔案,生成的位置(目標包),原始碼資料夾--> <sqlMapGenerator targetPackage="sqlmap" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!--XML對應的Mapper類--> <javaClientGenerator type="XMLMAPPER" targetPackage="zhaowd.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!--下面是資料庫表名和專案中需要生成類的名稱,建議和資料庫保持一致,如果有多個表,新增多個節點即可 enable*ByExample 是否生成 example類--> <table schema="zhaowd" tableName="user_info" domainObjectName="UserInfo" enableCountByExample="false" enableSelectByExample="true" enableUpdateByExample="false" enableDeleteByExample="false"> </table> </context> </generatorConfiguration>
使用方法:右鍵專案–>run as–>maven Build 自動生成mybatis需要的內容,mapper介面,mapper.xml,表實體 預設直接覆蓋原有的,所以儘量不要在生成的檔案中編寫自己的程式碼,使用單獨的檔案,防止覆蓋
- 分頁
mybatis自帶方法裡的分頁引數是對結果集進行分頁的,就是假分頁
方法1:就是使用sql語句的拼裝去分頁,直接使用資料庫的sql
方法2:使用分頁外掛,比如pagehelper
- pom配置見上面mybatis的配置
- 使用說明:再查詢之前增加PageHelper.startPage(當前頁,限制數量);即可
- 注意事項見圖片程式碼註釋
使用過程中的異常
- Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.
Caused by: java.lang.IllegalStateException: Cannot enable lazy loading because Javassist is not available. Add Javassist to your classpath.
at org.apache.ibatis.executor.loader.javassist.JavassistProxyFactory.<init>(JavassistProxyFactory.java:55)
at org.apache.ibatis.session.Configuration.<init>(Configuration.java:131)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.<init>(XMLConfigBuilder.java:86)
at org.apache.ibatis.builder.xml.XMLConfigBuilder.<init>(XMLConfigBuilder.java:82)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:77)
... 25 more
Caused by: java.lang.ClassNotFoundException: Cannot find class: javassist.util.proxy.ProxyFactory
缺少jar依賴
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
- Caused by: java.lang.RuntimeException: MemberAccess implementation must be provided! ognl版本不對,可能太高了
修改成:
<dependency>
<groupId>ognl</groupId>
<artifactId>ognl</artifactId>
<version>2.7.3</version>
</dependency>
原始碼分析
程式呼叫鏈條如下圖所示:
1.流程呼叫圖(簡化版)
2.複雜點的(這有點亂,結合簡化版的看)
- 目錄結構說明 annotations:註解定義 binding:繫結mapper介面與mapper.xml的關係 builder:註解+配置解析 cache:快取 cursor: datasource:資料來源 exceptions:異常 executor:sql的實際執行者 io:讀檔案 jdbc:底層相關 lang: logging:日誌 mappering:對映到實體 parsing:解析配置+註解 plugin:外掛,攔截器 reflection:反射 scripting:引數處理 session:session transaction: type:型別
原始碼
原始碼的呼叫流程見上圖
學習:
- Configuration
目前mybatis支援兩種方式的實現功能
- 程式設計式:只是單純的使用mybaits去作為持久化層去使用,mybatis提供xml的形式去簡化配置
- 整合式:比如整合在spring中使用,可以使用Configuration去設定配置引數 程式設計式在使用過程中,也會將xml對映到Configuration上 Configuration與SqlSessionFactory一一對應
- 快取
-
一級快取:預設開啟,session級別的,第一查詢進行快取,第二次查詢從快取裡取
- 如果同一個sesssion,在兩次查詢之間有更新資料的操作(update,delete)並提交,session的所有快取都會清
- 如果有不同的session,在兩次查詢之間有更新資料的操作(update,delete),第二次查詢的資料就是髒資料了,session之間快取都是獨立的 一級快取是在取二級快取之後(如果二級開關開啟的話)
設定一級快取的時候會使用一個佔位符去佔位,作用:比如在聯合查詢中,第二個sql在執行時,可能會命中第二個sql在單獨執行時的一級快取,如果獲取到快取的值是這個佔位符,表示這個快取不能使用;應該就是這個聯合查詢的第二個sql不載入到快取裡,由正在處理的加
-
二級快取:預設關閉,一般使用第三方實現(redies),nameSpace級別的,共享給所有的sqlSession
- 同一個namespace下的upd,del會清掉該space下的快取同一個namespace下的upd,del會清掉該space下的快取
- 如果是關聯查詢,快取也只是當前namespace下的;如果另外一個namespace對資料有更新,不會影響其他namespace下的快取,哪怕是關聯查詢的第二條sql
-
-
plugin機制 攔截
-
ObjectFactory 建立結果物件的例項
- 拿到結果集,建立結果對映物件,就是實體物件(通過反射呼叫無參構造,如有自定義objectFactory,呼叫create建立)之後;這個時候還沒有對映
- 入參設定同理
-
laze Loading機制 *
- 如果lazyLoading開啟,預設是javassist,可選cglib/自定義;會通過config去建立一個proxyFactory(java、cglib)的代理的代理物件 位置:org.apache.ibatis.executor.resultset.DefaultResultSetHandler.createResultObject(ResultSetWrapper, ResultMap, ResultLoaderMap, String)
-
異常機制
-
log