文章目錄
一:mybatis的使用
mybatis使用有2種方式:
1:老版本ibatis中直接使用sqlsession的api,具體如下
引入mybatis的pom座標
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>x.x.x</version>
</dependency>
mybatis主要通過一個SqlSessionFactoryBulder,在解析mybatis的配置下,創建SqlSessionFactory,然後通過SqlSessionFactory創建SqlSqlssion來操作數據庫
獲取SqlSessionFactory(兩種方式:使用xml和使用代碼方式)
方式一:通過mybatisConfig.xml獲取
創建mybatisConfig.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>
<!-- 數據庫連接信息配置 -->
<properties resource="mybatis/mybatis.properties"></properties>
<!--mybatis運行時的一些配置-->
<settings>
<setting name="" value=""/>
</settings>
<!-- 針對單個別名定義type:類型的路徑 alias:別名 -->
<!-- <typeAlias type="cn.itcast.mybatis.po.User" alias="user"/> -->
<!-- 批量別名定義 指定包名,mybatis自動掃描包中的po類,自動定義別名,別名就是類名(類名小寫)-->
<!-- 別名定義 -->
<typeAliases>
<package name="com.test.model"/>
</typeAliases>
<environments default="${defaultActive}">
<!--開發環境:事務處理器以及數據源-->
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${dev_url}"/>
<property name="username" value="${dev_username}"/>
<property name="password" value="${dev_password}"/>
</dataSource>
</environment>
<!--測試環境-->
<environment id="test">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${test_url}"/>
<property name="username" value="${test_username}"/>
<property name="password" value="${test_password}"/>
</dataSource>
</environment>
</environments>
<!--引入mapper.xml文件-->
<mappers>
<mapper resource="mybatis/mapper/testMapper.xml"/>
</mappers>
</configuration>
testMapper.xml如下:
<?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="mybatis.mapper">
<!--簡單查詢-->
<select id="selectById" resultType="com.test.model.User"
parameterType="java.lang.String" >
select * from user where id = #{pid}
</select>
</mapper>
TestMybatis.java
String resource = "mybatis/mybatisConfig.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
String pid = "1";
List<User> selectList = session.selectList("mybatis.mapper.selectById", pid);
System.out.println(selectList.size());
2:面向接口編程,使用mapper
使用mapper接口,必須保證接口全類名和mapper.xml的namespace一樣,方法名和mapper.xml中對應sql的id相同。
二:配置解析
總的來說,mybatis的所有配置基本上都會解析到Configuration類中,本文只看解析過程,暫時不管應用。
很顯然,mybatis的配置解析代碼在SqlSessionFactoryBuilder的build方法。
重點顯然在解析配置到Configuration過程。
parseConfiguration(parser.evalNode("/configuration"));
1:properties:外部配置
2:typeAliases:類型別名配置
如何設置別名?
typeAliasRegistry.registerAlias(clazz);
typeAliasRegistry在Configuiration中。內部包含默認的一些別名。
3:plugins:插件配置
插件配置解析,實例化
4:settings:全局運行參數
都是一些鍵值對,在Configuration類中有對應字段保存。能夠改變mybatis的運行行爲
下面是setting的各個配置項說明
參考:https://www.cnblogs.com/LingCoder/p/9063730.html
5:environments:數據源和事務處理器
<environments default="development">
<environment id="development">
<!-- 配置事務處理器 -->
<transactionManager type="JDBC" />
<!-- 配置數據庫連接信息 -->
<dataSource type="POOLED">
<property name="driver" value="${derby.driver}" />
<property name="url" value="${derby.url}" />
<property name="username" value="${derby.user}" />
<property name="password" value="${derby.pwd}" />
</dataSource>
</environment>
</environments>
environment 的id唯一標識運行環境,environments的default指定默認運行環境。可以切換開發測試環境。
事務處理器怎麼創建的呢?
在Configuration的構造器中設置別名,都是事務工廠的實現:
數據源又是怎麼創建的呢?
在Configuration中的構造器設置的datasource別名,都是數據源工廠的實現:
6:mapper:映射器配置
<mappers>
<!--<package name=""></package>-->
<mapper resource="testMapper.xml"></mapper>
<mapper resource="testMapper2.xml"></mapper>
</mappers>
有2種方式:
- 統一配置:package
- 單獨配置:mapper
那麼通過pakage配置,如何解析呢?
配置package的話,就是mapper接口所在的包名。並且對應的mapper.xml要和接口名同名,且在同一個包下。
加載後mapper存放在映射器註冊器中:MapperRegistry (在Configuration中初始化),然後解析對應的mapper.xml
1. mapper開啓二級緩存引用:cache-ref
配置完成後,在使用的時候,能根據Configuration中的namespace引用關係,拿到緩存引用的對象,進而引用其它映射器的緩存。
2.mapper開啓二級緩存:cache
緩存配置解析邏輯:
private void cacheElement(XNode context) throws Exception {
if (context != null) {
// 如果自定義緩存實現,就需要指定type字段,否則使用默認實現(Configuration中指定:typeAliasRegistry.registerAlias("PERPETUAL", PerpetualCache.class);)
String type = context.getStringAttribute("type", "PERPETUAL");
Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
// 確定緩存回收策略的實現
String eviction = context.getStringAttribute("eviction", "LRU");
Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
Long flushInterval = context.getLongAttribute("flushInterval");
Integer size = context.getIntAttribute("size");
boolean readWrite = !context.getBooleanAttribute("readOnly", false);
boolean blocking = context.getBooleanAttribute("blocking", false);
//讀入額外的配置信息,易於第三方的緩存擴展,例:
// <cache type="com.domain.something.MyCustomCache">
// <property name="cacheFile" value="/tmp/my-custom-cache.tmp"/>
// </cache>
Properties props = context.getChildrenAsProperties();
//調用builderAssistant.useNewCache
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
}
}
- 確定緩存處理的實現類:
默認使用:PERPETUAL (別名在Configuration配置)
typeAliasRegistry.registerAlias(“PERPETUAL”, PerpetualCache.class); - 後面分別確認cache的幾個屬性
- 關鍵部分:
builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
3. resultMap解析
這個元素很重要,此處簡單瞭解,留待後面重點分析。
<resultMap id="trrr" type="txd.test.model.Blog">
<id column="id" javaType="string" property="id"></id>
<result column="author_id" javaType="string" property="authorId"></result>
<result column="title" javaType="string" property="title"></result>
</resultMap>
相應解析邏輯:
以id子節點爲例,看看如何解析?
List<ResultFlag> flags = new ArrayList<ResultFlag>();
if ("id".equals(resultChild.getName())) {
flags.add(ResultFlag.ID);
}
//調5.1.1 buildResultMappingFromContext,得到ResultMapping
resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
跟進代碼,其實就是把id子節點的各個屬性解析出來。傳入 ,通過構造者模式得到ResultMapping。所有節點解析完就是一個List,然後構建ResultMap。最後加入到Configuration中 (key是resultmap的id)
protected final Map<String, ResultMap> resultMaps = new StrictMap(“Result Maps collection”);
4.sql片段解析和select節點解析
首先放入XMLMapperBuilder的 Map<String, XNode> sqlFragments;中,具體解析是在select|insert|update|delete的解析過程中使用
那麼select|insert|update|delete怎麼解析的呢?
看一個簡單例子:
<select id="selectById" resultMap="trrr" >
select * from BLOG where id = #{id}
</select>
- 首先是獲取select節點的各種屬性值,以下這些
- 看一下緩存相關的
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = context.getBooleanAttribute(“flushCache”, !isSelect);
//是否要緩存select結果
boolean useCache = context.getBooleanAttribute(“useCache”, isSelect);
如果是select語句,默認是不清理緩存的,除非flushCache指定true(默認false)
而且select默認是使用緩存的,除非(useCache指定爲false)
-
sql片段應用
參考一篇博客:https://my.oschina.net/zudajun/blog/687326 -
sql解析
最終解析成MappedStatement,此過程會用到SqlSource(動態sql解析),BoundSql
具體參考網上的2篇博客:
https://my.oschina.net/zudajun/blog/735553
https://my.oschina.net/zudajun/blog/735731
三:參考博客
https://my.oschina.net/zudajun?tab=newest&catalogId=3532897