写给自己的:经过半个月Mybatis的学习,对Mybatis的基本用法有了一定的掌握。但是以往学习其它框架的经历告诉我,学习完后不抓紧总结很快又会忘记,遂从头开始梳理总结一遍。从Mybatis的核心组件入手是有效梳理和总结Mybatis框架的有效路径,这些总结不会深入底层框架的源码,专注于上层接口和类的一些分析,因为本人的开发经验都还很欠缺,过早去纠结源码收获必不多。
Mybatis的核心组件有:SqlSessionFactory、SqlSession、Mapper、TypeHandler。前面对它们的总结主要是集中于使用环节,这个系列将集中于它们比较浅显的创建过程和更加细节性的东西。本系列针对Mybatis3.4.5源码进行阐述。
一、SqlSessionFactory
1、细说SqlSessionFactory创建过程
SqlSessionFactory由SqlSessionFactoryBuilder通过xml配置文件或者Configuration配置类对象产生。
我们通常是通过
InputStream is = Resources.getResourceAsStream(String baseConfigXmlFilePath);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(is)
这两个步骤获取SqlSessionFactory接口对象
那么其中Mybatis帮我们做了哪些事呢?
首先看SqlSessionFactoryBuilder这个类
public class SqlSessionFactoryBuilder {
public SqlSessionFactory build(Reader reader) {
return build(reader, null, null);
}
public SqlSessionFactory build(Reader reader, String environment) {
return build(reader, environment, null);
}
public SqlSessionFactory build(Reader reader, Properties properties) {
return build(reader, null, properties);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment) {
return build(inputStream, environment, null);
}
public SqlSessionFactory build(InputStream inputStream, Properties properties) {
return build(inputStream, null, properties);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
inputStream.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
}
从SqlSessionFactoryBuilder这个类的源码中可以看出,它有9个build方法的重载。
根本的有三个重载的build方法:
1、 public SqlSessionFactory build(Reader reader, String environment, Properties properties)
2、 public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
3、 public SqlSessionFactory build(Configuration config)
结合Mybatis的基础配置文件结构,整个SqlSessionFactory的创建过程就非常明了了。<Configuration>与Configuration配置类对应,它涵盖了创建SqlSessionFactory所需要的全部配置信息。
整个流程如下:
baseConfigXmlFile-------------->XmlConfigBuilder解析---------->Configuration类对象----------->SqlSessionFactoryBuilder--------------->SqlSessionFactory对象。
接下来细说下面这个方法:
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties)
enviroment是指定默认的数据库环境如下所示
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="driver.encoding" value="utf8" />
<property name="url" value="jdbc:mysql://localhost/book"/>
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
当这个参数不为null时,将覆盖基础配置文件中的值,可以在一个基础配置文件中配置多个数据库环境,然后在创建不同数据库的SqlSessionFactory比如存在数据库环境配置db1、db2
<environments default="development">
<environment id="db1">
......
</environment>
<environment id="db2">
......
</environment>
</environments>
String baseConfigFilePath = "mybatis-config.xml";
InputStream is1 = Resources.getResourceAsStream(baseConfigFilePath);
InputSream is2 = Resources.getResourceAsStream(baseConfigFilePath);
SqlSessionFactory db1SqlSessionFactory = new SqlSessionFactoryBuilder().build(is1, "db1");
SqlSessionFactory db1SqlSessionFactory = new SqlSessionFactoryBuilder().build(is2, "db2");
注意这里:虽然配置文件是同一个,但是不能共享同一个InputSream对象,因为SqlSessionFactoryBuilder在创建完SqlSessionFactory对象后会关闭InputStream对象。
再看properties这个参数,可以通过properties参数配置属性信息,同样它将覆盖基础配置文件中的相同属性名称的属性的值。
String resource = "mybatis-config.xml"//基础配置文件
InputStream inputStream;
InputSream is = Resource.getResourceAsStream("jdbc.properties");
Properties props = new Properties();
props.load(is);
String userName = props.getProperty("database.username");
String password = props.getProperty("database.password");
//解密用户名和密码
props.put("database.username", CodeUtils.decode(userName));
props.put("database.password", CodeUtils.decode(password));
inputStream = Resource.getResourceAsStream(resource);
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream, props);
三种配置方式优先级:代码方式>properties文件方式>property子元素方式
当SqlSessionFactory对象创建完成后,我们如果需要修改配置信息怎么办呢?
SqlSessionFactory对象保存了创建它的Configuration对象的信息,我们可以通过
SqlSessionFactory对象的getConfiguration()方法获取Configuration配置对象。
而Confiration配置对象中,保存了各种注册器的引用(别名注册器、类型转换器等)
可以通过这些方法动态地改变配置信息。如我们可以获取别名注册器在代码中动态地注册别名:
Configuration configuration = factory.getConfiguration();
TypeAliasRegistry typeAliasRegistry = configuration.getTypeAliasRegistry();
typeAliasRegistry.registerAlias("key", "value");