本文讲解 MyBatis 四大核心概念(SqlSessionFactoryBuilder、SqlSessionFactory、SqlSession、Mapper。
了解了这四大核心,可知 MyBatis 。
SqlSessionFactoryBuilder
从命名上可以看出,这个是一个 Builder 模式的,用于创建 SqlSessionFactory 的类。SqlSessionFactoryBuilder 根据配置来构造 SqlSessionFactory。
SqlSessionFactory
是用于生产 SqlSession 的工厂。
SqlSession
即可发送SQL执行返回结果,又可获取mapper的接口。相当于一个数据库连接对象,可以在一个事务里面执行多条SQL,通过commit、rollback进行提交或回滚事务。
SQL Mapper
由一个Java接口和XML文件(或注解)构成。根据编写的SQL和映射规则,实现对数据库的访问,并返回结果。存活于一个请求中,一但请求完毕后,就会废弃。
. 1.mybatis配置文件
SqlMapConfig.xml,此文件作为mybatis的全局配置文件,配置了mybatis的运行环境等信
息。
Mapper.xml,此文件作为mybatis的sql映射文件,文件中配置了操作数据库的sql语句。此
文件需要在SqlMapConfig.xml中加载。
2. SqlSessionFactory
通过mybatis环境等配置信息构造SqlSessionFactory,即会话工厂。
3. sqlSession
通过会话工厂创建sqlSession即会话,程序员通过sqlsession会话接口对数据库进行增删改查操
作。
4. Executor执行器
mybatis底层自定义了Executor执行器接口来具体操作数据库,Executor接口有两个实现,一个是
基本执行器(默认)、一个是缓存执行器,sqlsession底层是通过executor接口操作数据库的。
5. Mapped Statement
它也是mybatis一个底层封装对象,它包装了mybatis配置信息及sql映射信息等。mapper.xml文
件中一个select\insert\update\delete标签对应一个Mapped Statement对象,
select\insert\update\delete标签的id即是Mapped statement的id。
Mapped Statement对sql执行输入参数进行定义,包括HashMap、基本类型、pojo,Executor通
过Mapped Statement在执行sql前将输入的java对象映射至sql中,输入参数映射就是jdbc编程中
对preparedStatement设置参数。
Mapped Statement对sql执行输出结果进行定义,包括HashMap、基本类型、pojo,Executor通
过Mapped Statement在执行sql后将输出结果映射至java对象中,输出结果映射过程相当于jdbc
编程中对结果的解析处理过程。
我们在使用 MyBatis 时,第一步要做的事情一般是根据配置文件构建 SqlSessionFactory对象。我们首先会使用 MyBatis 提供的工具类 Resources 加载配置文件,得到一个输入流。然后再通过 SqlSessionFactoryBuilder 对象的 build 方法构建 SqlSessionFactory 对象。这里的 build 方法是我们分析配置文件解析过程的入口方法。
下面我们来看一下这个方法的代码:
public SqlSessionFactory build(InputStream inputStream) {
// 调用重载方法
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 创建配置文件解析器
XMLConfigBuilder parser =
new XMLConfigBuilder(inputStream, environment, properties);
// 调用 parse 方法解析配置文件,生成 Configuration 对象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("……", e);
} finally {
ErrorContext.instance().reset(); try {
inputStream.close();
} catch (IOException e) {
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
public XMLConfigBuilder(Reader reader) {
this(reader, null, null);
}
public XMLConfigBuilder(Reader reader, String environment) {
this(reader, environment, null);
}
public XMLConfigBuilder(Reader reader, String environment, Properties props) {
this(new XPathParser(reader, true, props, new XMLMapperEntityResolver()), environment, props);
}
public XMLConfigBuilder(InputStream inputStream) {
this(inputStream, null, null);
}
public XMLConfigBuilder(InputStream inputStream, String environment) {
this(inputStream, environment, null);
}
public XMLConfigBuilder(InputStream inputStream, String environment, Properties props) {
this(new XPathParser(inputStream, true, props, new XMLMapperEntityResolver()), environment, props);
}
private XMLConfigBuilder(XPathParser parser, String environment, Properties props) {
super(new Configuration());//调用父类的构造方法
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
this.environment = environment;
this.parser = parser;
}
public Configuration parse() {
if (parsed) {
//判断Configuration是否解析过,Configuration是全局变量,只需要解析创建一次即可
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
parseConfiguration(parser.evalNode("/configuration"));//调用下面的方法,parser.evalNode("/configuration")解析XML配置的configuration节点的内容,得到XNode对象
return configuration;
}
//根据root中存储的是configuration节点的内容
private void parseConfiguration(XNode root) {
try {
Properties settings = settingsAsPropertiess(root.evalNode("settings"));//设置settings配置
//issue #117 read properties first
propertiesElement(root.evalNode("properties"));//设置properties配置
loadCustomVfs(settings);
typeAliasesElement(root.evalNode("typeAliases"));//设置typeAliases配置
pluginElement(root.evalNode("plugins"));//设置plugins配置
objectFactoryElement(root.evalNode("objectFactory"));//设置objectFactory配置
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));//设置objectWrapperFactory配置
reflectorFactoryElement(root.evalNode("reflectorFactory"));//设置reflectFactory配置
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
environmentsElement(root.evalNode("environments"));//设置environments配置
databaseIdProviderElement(root.evalNode("databaseIdProvider"));//设置databaseIdProvider配置
typeHandlerElement(root.evalNode("typeHandlers"));//设置typeHandlers配置
mapperElement(root.evalNode("mappers"));//设置mappers配置
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
sqlsession执行
制定sqlsession接口和api方法
创建SqlSession
创建Sqlsession需要先创建SqlSessionFactory,通过SqlSessionFactoryBuilder使用构
建者模式来创建,此时需要Configuration对象去创建SqlSessionFactory
执行sqlsession:参数有两个(statementId和参数对象)
根据statementId,去Configuration中的MappedStatement集合中查找对应的
MappedStatement对象。
取出MappedStatement中的SQL信息
取出MappedStatement中的statementType,用来创建Statement对象
取出MappedStatement中的Configuration对象,通过Configuration对象,获取
DataSource对象,通过DataSource对象,创建Connection,通过Connection创
建Statement对象。
设置参数
执行preparedStatement.setInt(1,value);
遍历List集合(参数名称、属性类型、顺序)
判断是否是集合类型、8种基本类型、String类型、引用类型
基本类型的话,传过来的参数就是SQL的参数值
引用类型的话,根据参数名称,获取引用类型对应的属性值
调用setXXX方法赋值
执行Statement
executeQuery方法,获取ResultSet结果集
处理结果集
遍历结果集ResultSet
取出ResultSet中的所有列的名称和值和类型,存储到一个集合中
取出MappedStatement中的resultTypeClass,反射进行实例化。
遍历上面的集合,根据集合中的列的名称给属性赋值
public final class MappedStatement {
private String resource;
private Configuration configuration;
private String id;
private Integer fetchSize;
private Integer timeout;
private StatementType statementType;
private ResultSetType resultSetType;
private SqlSource sqlSource;
private Cache cache;
private ParameterMap parameterMap;
private List<ResultMap> resultMaps;
private boolean flushCacheRequired;
private boolean useCache;
private boolean resultOrdered;
private SqlCommandType sqlCommandType;
private KeyGenerator keyGenerator;
private String[] keyProperties;
private String[] keyColumns;
private boolean hasNestedResultMaps;
private String databaseId;
private Log statementLog;
private LanguageDriver lang;
private String[] resultSets;
MappedStatement() {
}