文章目录
一: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
有3种方式配置
- property子元素:
<properties> <property name="" value=""/> </properties>
- 配置文件(resource对应本地文件,url网络文件):
<properties resource="jdbc.properties"/>
- XMLConfigBuilder构造方法参数传递配置
加载顺序:
首先加载property子元素,然后加载resource或者url指定的配置文件(key重名则覆盖),最后加载方法参数传递的属性(key重名则覆盖(方法参数传递:XMLConfigBuilder的构造方法private XMLConfigBuilder(XPathParser parser, String environment, Properties props)。
后加载的覆盖前面加载的,所以相同配置优先级。代码 > 配置文件 > property子元素
org.apache.ibatis.builder.xml.XMLConfigBuilder#propertiesElement
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