主启动类
public class MybatisHelloWorld {
public static void main(String[] args) throws Exception {
String resource = "org/mybatis/config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
List users = mapper.getUsers(1);
session.close();
}
}
userMapper.class
public interface UserMapper {
@Select({"select * from user where age=#{age}"})
List getUsers(int age);
}
config.xml
//控制台输出sql
Mybatis通过session来进行数据库的操作,sqlSessionFactory封装了session的创建,而SqlSessionFactoryBuilder又封装了sqlSessionFactory的创建
从上面代码来看总共做了两件事
先来看如何将xml配置文件封装为对象的
new SqlSessionFactoryBuilder().build(inputStream);
这里使用构造者模式来创建一个sqlSessionFactory,里面使用重载
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
最终调用
SqlSessionFactoryBuilder.java
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//创建一个xml解析类
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//解析xml中配置,转换为configuration类
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.
}
}
}
mybatis是把一些配置类以及它自己需要使用的各种类封装成一个大的config对象
org.apache.ibatis.session.Configuration 里面有很多环境,mapper等等的信息,内容太多就不粘贴了
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) {
//创建了一个Configuration 对象
super(new Configuration());
ErrorContext.instance().resource("SQL Mapper Configuration");
this.configuration.setVariables(props);
this.parsed = false;
//这一行设置环境id
this.environment = environment;
this.parser = parser;
}
XMlConfigBuilder类关系图

BaseBuilder.java
public BaseBuilder(Configuration configuration) {
this.configuration = configuration;
this.typeAliasRegistry = this.configuration.getTypeAliasRegistry();
this.typeHandlerRegistry = this.configuration.getTypeHandlerRegistry();
}
解析主配置文件.xml
SqlSessionFactoryBuilder.java
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
//....
return build(parser.parse());
//....
}
public Configuration parse() {
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//读取configuration节点下的node传入
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
//读取properties
propertiesElement(root.evalNode("properties"));
//读取一些setting设置
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
//注册别名
typeAliasesElement(root.evalNode("typeAliases"));
//插件,进行增强-先略过
pluginElement(root.evalNode("plugins"));
//对象工厂,自定义实例化方法--略过
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectionFactoryElement(root.evalNode("reflectionFactory"));
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//配置环境
environmentsElement(root.evalNode("environments"));
//数据厂商表示--略过
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
typeHandlerElement(root.evalNode("typeHandlers"));
//配置mapper
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
解析的东西很多,我们只先看environments和mapper
XMLConfigBuilder.java
private void environmentsElement(XNode context) throws Exception {
if (context != null) {
if (environment == null) {
environment = context.getStringAttribute("default");
}
for (XNode child : context.getChildren()) {
String id = child.getStringAttribute("id");
//可以配置多个环境,判断是不是指定的环境
if (isSpecifiedEnvironment(id)) {
//获取事物管理器,创建事物管理器工厂
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//获取datasource工厂-UnpooledDataSourceFactory默认
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
}
}
}
}
进入发现第一件是就是判断环境,没有指定就使用中default的环境id,在上面的XMLConfigBuilder的有参构造中this.environment = environment;将环境配置设置给了XMLConfigBuilder的environment 点我跳转到XMLConfigBuilder-有参构造
我们在使用时可以这样,在配置文件xml中,声明多个环境
主启动类中,手动指明一个配置环境
public static void main(String[] args) throws Exception {
//....
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream,"myTest");
//....
}
回到代码第一步就是判断用户选择的那个id的环境,之后创建事务管理器
XMLConfigBuilder.java
private void environmentsElement(XNode context) throws Exception {
//..
TransactionFactory txFactory = transactionManagerElement(child.evalNode("transactionManager"));
//..
}
private TransactionFactory transactionManagerElement(XNode context) throws Exception {
if (context != null) {
//获取我们在xml中声明的事务管理类型,当前是JDBC
String type = context.getStringAttribute("type");
//获取节点下的子节点,当前案例没有子节点
Properties props = context.getChildrenAsProperties();
//这里只是创建工厂类
TransactionFactory factory = (TransactionFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a TransactionFactory.");
}
这里调用resolveClass()方法是父类BaseBuilder的方法
一直点进去最后如下
TypeAliasRegistry.java
public class TypeAliasRegistry {
private final Map> TYPE_ALIASES = new HashMap>();
//.....
public Class resolveAlias(String string) {
try {
if (string == null) {
return null;
}
// issue #748
String key = string.toLowerCase(Locale.ENGLISH);
Class value;
if (TYPE_ALIASES.containsKey(key)) {
value = (Class) TYPE_ALIASES.get(key);
} else {
value = (Class) Resources.classForName(string);
}
return value;
} catch (ClassNotFoundException e) {
throw new TypeException("Could not resolve type alias '" + string + "'. Cause: " + e, e);
}
}
}
判断这个TYPE_ALIASES map中是否存在JDBC这个key,如果不存在,则去加载
按理来说这里应该是不存在的,因为你在TypeAliasRegistry中找不到任何一个地方对TYPE_ALIASES添加一个JDBC的key
但是实际它却存在这个key,在Configuration类的无参构造时,对这个TypeAliasRegistry进行的添加
public Configuration() {
typeAliasRegistry.registerAlias("JDBC", JdbcTransactionFactory.class);
//...
typeAliasRegistry.registerAlias("POOLED", PooledDataSourceFactory.class);
languageRegistry.setDefaultDriverClass(XMLLanguageDriver.class);
//......
}
这个过程如下图

回到代码因为我们这次案例的配置为所以不会存在子节点context.getChildrenAsProperties();返回的结果0个配置项,transactionManagerElement方法结束
之后去解析数据库配置文件
XMLConfigBulider.java
private void environmentsElement(XNode context) throws Exception {
//...
//获取datasource工厂-UnpooledDataSourceFactory默认
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
//...
}
和解析环境基本一样的代码,不过解析dataSource的时候,子节点就不为空了
会有四个属性
private DataSourceFactory dataSourceElement(XNode context) throws Exception {
if (context != null) {
String type = context.getStringAttribute("type");
Properties props = context.getChildrenAsProperties();
//type为POOLED的默认实现是PooledDataSourceFactory
DataSourceFactory factory = (DataSourceFactory) resolveClass(type).newInstance();
factory.setProperties(props);
return factory;
}
throw new BuilderException("Environment declaration requires a DataSourceFactory.");
}
进入factory.setProperties(props);
public class UnpooledDataSourceFactory implements DataSourceFactory {
private static final String DRIVER_PROPERTY_PREFIX = "driver.";
private static final int DRIVER_PROPERTY_PREFIX_LENGTH = DRIVER_PROPERTY_PREFIX.length();
protected DataSource dataSource;
//无参默认将dataSource设置为UnpooledDataSource
public UnpooledDataSourceFactory() {
this.dataSource = new UnpooledDataSource();
}
@Override
public void setProperties(Properties properties) {
Properties driverProperties = new Properties();
//将工厂对象进行包装
MetaObject metaDataSource = SystemMetaObject.forObject(dataSource);
for (Object key : properties.keySet()) {
String propertyName = (String) key;
//如果存在driver
if (propertyName.startsWith(DRIVER_PROPERTY_PREFIX)) {
String value = properties.getProperty(propertyName);
driverProperties.setProperty(propertyName.substring(DRIVER_PROPERTY_PREFIX_LENGTH), value);
//如果当前属性在类中有对应的可以写入的属性
} else if (metaDataSource.hasSetter(propertyName)) {
String value = (String) properties.get(propertyName);
Object convertedValue = convertValue(metaDataSource, propertyName, value);
metaDataSource.setValue(propertyName, convertedValue);
} else {
throw new DataSourceException("Unknown DataSource property: " + propertyName);
}
}
//如果属性不为空,则设置给meatDataSource
if (driverProperties.size() > 0) {
metaDataSource.setValue("driverProperties", driverProperties);
}
}
//......
}
一顿设置后回到XMLConfigurationBuilder中的environmentsElement方法
最后将读取出的配置封装为Environment,赋值给BaseBuilder中的environment
private void environmentsElement(XNode context) throws Exception {
//.....
DataSourceFactory dsFactory = dataSourceElement(child.evalNode("dataSource"));
DataSource dataSource = dsFactory.getDataSource();
Environment.Builder environmentBuilder = new Environment.Builder(id)
.transactionFactory(txFactory)
.dataSource(dataSource);
configuration.setEnvironment(environmentBuilder.build());
//.....
}
回到XMLConfigBuilder中的parseConfiguration
private void parseConfiguration(XNode root) {
//.....
//配置mapper
mapperElement(root.evalNode("mappers"));
}
我们只看根据包扫描的,给Configuration中添加了mapper包名
private void mapperElement(XNode parent) throws Exception {
if (parent != null) {
for (XNode child : parent.getChildren()) {
//使用包,默认查找指定包下位置
if ("package".equals(child.getName())) {
String mapperPackage = child.getStringAttribute("name");
configuration.addMappers(mapperPackage);
}
//.....
}
}
}
Configuration.java
public void addMappers(String packageName) {
mapperRegistry.addMappers(packageName);
}
MapperRegistry.java
public void addMappers(String packageName) {
addMappers(packageName, Object.class);
}
//根据包名去查询该包下的类
public void addMappers(String packageName, Class> superType) {
ResolverUtil> resolverUtil = new ResolverUtil>();
resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
Set>> mapperSet = resolverUtil.getClasses();
for (Class> mapperClass : mapperSet) {
addMapper(mapperClass);
}
}
之后就是动态代理对应的mapper
MapperRegistry.java
public void addMapper(Class type) {
if (type.isInterface()) {
//判断是否已经存在
if (hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
knownMappers.put(type, new MapperProxyFactory(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
knownMappers.remove(type);
}
}
}
}
public class MapperProxyFactory {
private final Class mapperInterface;
private final Map methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class getMapperInterface() {
return mapperInterface;
}
public Map getMethodCache() {
return methodCache;
}
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
}
主要来看这段
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);
parser.parse();
MapperAnnotationBuilder.java
public class MapperAnnotationBuilder {
private final Set> sqlAnnotationTypes = new HashSet>();
private final Set> sqlProviderAnnotationTypes = new HashSet>();
//....
/**
* 在构造时添加mybatis的注解
*/
public MapperAnnotationBuilder(Configuration configuration, Class> type) {
String resource = type.getName().replace('.', '/') + ".java (best guess)";
this.assistant = new MapperBuilderAssistant(configuration, resource);
this.configuration = configuration;
this.type = type;
sqlAnnotationTypes.add(Select.class);
sqlAnnotationTypes.add(Insert.class);
sqlAnnotationTypes.add(Update.class);
sqlAnnotationTypes.add(Delete.class);
sqlProviderAnnotationTypes.add(SelectProvider.class);
sqlProviderAnnotationTypes.add(InsertProvider.class);
sqlProviderAnnotationTypes.add(UpdateProvider.class);
sqlProviderAnnotationTypes.add(DeleteProvider.class);
}
public void parse() {
String resource = type.toString();
if (!configuration.isResourceLoaded(resource)) {
loadXmlResource();
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
parseCache();
parseCacheRef();
Method[] methods = type.getMethods();
for (Method method : methods) {
try {
// issue #237
if (!method.isBridge()) {
parseStatement(method);
}
} catch (IncompleteElementException e) {
configuration.addIncompleteMethod(new MethodResolver(this, method));
}
}
}
parsePendingMethods();
}
}
void parseStatement(Method method) {
Class> parameterTypeClass = getParameterType(method);
LanguageDriver languageDriver = getLanguageDriver(method);
SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
//...
}
首先第一步是获取参数类型-代码如下,如果mapper的入参数量大于1,则返回的就是ParamMap.class
private Class> getParameterType(Method method) {
Class> parameterType = null;
Class>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i
之后获取语言解析,没有指定就去找默认-默认的是XMLLanguageDriver.class 还是在Configuration类无参构造时添加进去的点我跳转到Configuration-无参构造
private LanguageDriver getLanguageDriver(Method method) {
Lang lang = method.getAnnotation(Lang.class);
Class> langClass = null;
if (lang != null) {
langClass = lang.value();
}
return assistant.getLanguageDriver(langClass);
}
获取注解上的内容,以及封装sql就在这个方法
private SqlSource getSqlSourceFromAnnotations(Method method, Class> parameterType, LanguageDriver languageDriver) {
try {
//获取是否存在@Select,@Insert....
Class extends Annotation> sqlAnnotationType = getSqlAnnotationType(method);
//获取是否存在@SelectProvider,@InsertProvider...
Class extends Annotation> sqlProviderAnnotationType = getSqlProviderAnnotationType(method);
if (sqlAnnotationType != null) {
if (sqlProviderAnnotationType != null) {
throw new BindingException("You cannot supply both a static SQL and SqlProvider to method named " + method.getName());
}
Annotation sqlAnnotation = method.getAnnotation(sqlAnnotationType);
//获取注解上的值
final String[] strings = (String[]) sqlAnnotation.getClass().getMethod("value").invoke(sqlAnnotation);
//返回sqlSource
//这个时候还没有进行填充值
return buildSqlSourceFromStrings(strings, parameterType, languageDriver);
} else if (sqlProviderAnnotationType != null) {
Annotation sqlProviderAnnotation = method.getAnnotation(sqlProviderAnnotationType);
return new ProviderSqlSource(assistant.getConfiguration(), sqlProviderAnnotation);
}
return null;
} catch (Exception e) {
throw new BuilderException("Could not find value method on SQL annotation. Cause: " + e, e);
}
}
此时的strings值还是 select * from user where age = #{age} 需要给替换为 select * from user where age =?
private SqlSource buildSqlSourceFromStrings(String[] strings, Class> parameterTypeClass, LanguageDriver languageDriver) {
final StringBuilder sql = new StringBuilder();
for (String fragment : strings) {
sql.append(fragment);
sql.append(" ");
}
return languageDriver.createSqlSource(configuration, sql.toString().trim(), parameterTypeClass);
}
默认的语言驱动是XMLLanguageDriver
XMLLanguageDriver.java
首先判断注解上的内容是否存在脚本,在mybatis官网,动态SQL下的script有使用案例,使得在注解中可以像在xml中使用 之后在RewSqlSource中对sql进行解析 RewSqlSource.java 解析完最终结果如下 回到上个方法 将各种参数最后封装为一个MappedStatement,放入configuration中,这样一个addMapper的方法就结束了 之后回到SqlSessionFactory的build中,执行重载的build DefaultSqlSessionFactory.java 至此 回到主代码 开始分析sqlSessionFactory.openSession(); 点进入发现有两个实现类,在上面的build中已经明确了创建的就是DefaultSqlSessionFactory DefaultSqlSessionFactory.java 获取configuration中的事务工厂之后创建一个执行器 Configuration.java 这里缓存是默认开启的,所以最后返回的是一个 最后返回一个默认的 DefaultSqlSession.java 到这里session也创建完成了之后就是获取mapper执行查询了 DefaultSqlSession.java Configuration.java MapperRegistry.java MapperProxyFactory.java MapperProxy.java 动态代理来实现mapper的方法调用 当我们执行userMapper.getUsers()的时候,通过动态代理进入invoke方法,之后获取缓存的方法,进入 先找是否已经创建过这个方法的封装类了,如果没有则去创建 MapperMethod.java MapperMethod.java-SqlCommand.java 静态内部类 Configuration.java 可能忘了它什么时候添加进去的了,在那个小助手中的addMappedStatement方法,最后的时候进行的添加点我跳转到addMappedStatement 那么这里就直接走到最后的if了,将name和type赋值给SqlCommand,方法结束 之后还有创建MethodSignature MapperMethod.java-MethodSignature.java 静态内部类 走完这一系列后回到MapperProxy.java中的invoke方法,最后执行 MapperMethod.java 根据command的类型,当前这个案例是SELECT,进入后判断返回类型,当前是返回一个集合,returnsMany属性为ture,进入到 封装mapper入参,没有入参返回null,一个入参返回数组,多个入参返回ParamMap 最终执行到 DefaultSqlSession.java warpCollection方法对入参同一封装了一遍 DefaultSqlSession.java 之后进入executor.query() 第一步先获取该方法对应的sql,入参类型,入参参数 之后是创建缓存key 创建CacheKey作为缓存key的封装类,根据以下参数进行生成key 之后遍历 如果是数组就将每个元素取出然后执行doUpdate,否则直接执行 CacheKey.java 最后走到 CachingExecutor.java 因为是首次进入,没有缓存,直接到BaseExecutor.query方法 BaseExecutor.java 进入后判断如果queryStack==0并且当前MappedStatement声明了需要清除缓存,则去清除缓存 将queryStack++,根据CacheKey获取对应缓存,如果没有则去查询数据库 queryStack的作用 BaseExecutor.java 进入doQuery SimpleExecutor.java 创建statement执行类 这里使用的是#{} MappedStatement的getStatementType返回为PREPARED 最后返回 之后解析prepareStatement 获取连接之后解析statement PreparedStatementHandler.java 之后执行 DefaultParameterHandler.java BaseTypeHandler.java 最后回到SimpleExecutor类中的prepareStatement方法,返回PreparedStatement@Override
public SqlSource createSqlSource(Configuration configuration, String script, Class> parameterType) {
// issue #3
if (script.startsWith("public RawSqlSource(Configuration configuration, String sql, Class> parameterType) {
SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
Class> clazz = parameterType == null ? Object.class : parameterType;
sqlSource = sqlSourceParser.parse(sql, clazz, new HashMap
void parseStatement(Method method) {
Class> parameterTypeClass = getParameterType(method);
LanguageDriver languageDriver = getLanguageDriver(method);
SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver);
//从这里继续
if (sqlSource != null) {
Options options = method.getAnnotation(Options.class);
//mappedStatementId=类全限定+方法名
final String mappedStatementId = type.getName() + "." + method.getName();
//设置获取数据的大小
Integer fetchSize = null;
//设置此次查询超时时间
Integer timeout = null;
//https://blog.csdn.net/king101125s/article/details/104167493
StatementType statementType = StatementType.PREPARED;
//resultSet结果类型 FORWARD_ONLY 光标只能向前移动
ResultSetType resultSetType = ResultSetType.FORWARD_ONLY;
//设置sql类型,当前案例是SELECT
SqlCommandType sqlCommandType = getSqlCommandType(method);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
boolean flushCache = !isSelect;
boolean useCache = isSelect;
KeyGenerator keyGenerator;
String keyProperty = "id";
String keyColumn = null;
if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.UPDATE.equals(sqlCommandType)) {
// first check for SelectKey annotation - that overrides everything else
SelectKey selectKey = method.getAnnotation(SelectKey.class);
if (selectKey != null) {
keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver);
keyProperty = selectKey.keyProperty();
} else if (options == null) {
keyGenerator = configuration.isUseGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
} else {
keyGenerator = options.useGeneratedKeys() ? new Jdbc3KeyGenerator() : new NoKeyGenerator();
keyProperty = options.keyProperty();
keyColumn = options.keyColumn();
}
} else {
keyGenerator = new NoKeyGenerator();
}
if (options != null) {
flushCache = options.flushCache();
useCache = options.useCache();
fetchSize = options.fetchSize() > -1 || options.fetchSize() == Integer.MIN_VALUE ? options.fetchSize() : null; //issue #348
timeout = options.timeout() > -1 ? options.timeout() : null;
statementType = options.statementType();
resultSetType = options.resultSetType();
}
String resultMapId = null;
ResultMap resultMapAnnotation = method.getAnnotation(ResultMap.class);
if (resultMapAnnotation != null) {
String[] resultMaps = resultMapAnnotation.value();
StringBuilder sb = new StringBuilder();
for (String resultMap : resultMaps) {
if (sb.length() > 0) {
sb.append(",");
}
sb.append(resultMap);
}
resultMapId = sb.toString();
} else if (isSelect) {
resultMapId = parseResultMap(method);
}
//将参数传给小助手
assistant.addMappedStatement(
mappedStatementId,
sqlSource,
statementType,
sqlCommandType,
fetchSize,
timeout,
// ParameterMapID
null,
parameterTypeClass,
resultMapId,
getReturnType(method),
resultSetType,
flushCache,
useCache,
// TODO issue #577
false,
keyGenerator,
keyProperty,
keyColumn,
// DatabaseID
null,
languageDriver,
// ResultSets
null);
}
}
public MappedStatement addMappedStatement(
String id,
SqlSource sqlSource,
StatementType statementType,
SqlCommandType sqlCommandType,
Integer fetchSize,
Integer timeout,
String parameterMap,
Class> parameterType,
String resultMap,
Class> resultType,
ResultSetType resultSetType,
boolean flushCache,
boolean useCache,
boolean resultOrdered,
KeyGenerator keyGenerator,
String keyProperty,
String keyColumn,
String databaseId,
LanguageDriver lang,
String resultSets) {
if (unresolvedCacheRef) {
throw new IncompleteElementException("Cache-ref not yet resolved");
}
id = applyCurrentNamespace(id, false);
boolean isSelect = sqlCommandType == SqlCommandType.SELECT;
MappedStatement.Builder statementBuilder = new MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType)
.resource(resource)
.fetchSize(fetchSize)
.timeout(timeout)
.statementType(statementType)
.keyGenerator(keyGenerator)
.keyProperty(keyProperty)
.keyColumn(keyColumn)
.databaseId(databaseId)
.lang(lang)
.resultOrdered(resultOrdered)
.resulSets(resultSets)
.resultMaps(getStatementResultMaps(resultMap, resultType, id))
.resultSetType(resultSetType)
.flushCacheRequired(valueOrDefault(flushCache, !isSelect))
.useCache(valueOrDefault(useCache, isSelect))
.cache(currentCache);
ParameterMap statementParameterMap = getStatementParameterMap(parameterMap, parameterType, id);
if (statementParameterMap != null) {
statementBuilder.parameterMap(statementParameterMap);
}
MappedStatement statement = statementBuilder.build();
//这里将这个MappedStatement放入configuration
configuration.addMappedStatement(statement);
return statement;
}

public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//回到这里
return build(parser.parse());
}
//默认为DefaultSqlSessionFactory
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
public class DefaultSqlSessionFactory implements SqlSessionFactory {
private final Configuration configuration;
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
//.....
}
new SqlSessionFactoryBuilder().build(inputStream)这段代码的解析环境和加载mapper就分析完了sqlSessionFactory
public static void main(String[] args) throws Exception {
String resource = "org/mybatis/config.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
//..
}
@Override
public SqlSession openSession() {
//参数:执行器,默认为simple,每次关闭statement SimpleExecutor
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
configuration.getDefaultExecutorType()在Configuration类中获取的是本身的一个属性,类型是一个ExecutorType的枚举,默认为SIMPEprivate SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//获取配置类中的事务,datasource封装类
final Environment environment = configuration.getEnvironment();
//通过配置的环境中获取事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//创建对象/datasource/隔离等级/是否自动提交
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
executor = new CachingExecutor(executor);
}
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
CachingExecutor 包含着一个SimpleExecutorDefaultSqlSession public DefaultSqlSession(Configuration configuration, Executor executor, boolean autoCommit) {
this.configuration = configuration;
this.executor = executor;
this.dirty = false;
this.autoCommit = autoCommit;
}
session.getMapper
@Override
public public public protected T newInstance(MapperProxy
public class MapperProxycachedMapperMethod public MapperMethod(Class> mapperInterface, Method method, Configuration config) {
thicnblogs.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, method);
}
public SqlCommand(Configuration configuration, Class> mapperInterface, Method method) {
String statementName = mapperInterface.getName() + "." + method.getName();
MappedStatement ms = null;
//当程序走到这里的时候就会为true
if (configuration.hasStatement(statementName)) {
ms = configuration.getMappedStatement(statementName);
}
///......
if (ms == null) {
//.....
} else {
name = ms.getId();
type = ms.getSqlCommandType();
if (type == SqlCommandType.UNKNOWN) {
throw new BindingException("Unknown execution method for: " + name);
}
}
}
public boolean hasStatement(String statementName) {
return hasStatement(statementName, true);
}
public boolean hasStatement(String statementName, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
//主要这行
return mappedStatements.containsKey(statementName);
}
public MethodSignature(Configuration configuration, Method method) {
this.returnType = method.getReturnType();
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = (configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray());
this.mapKey = getMapKey(method);
this.returnsMap = (this.mapKey != null);
//是否存在@Param注解
this.hasNamedParameters = hasNamedParams(method);
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
this.params = Collections.unmodifiableSortedMap(getParams(method, this.hasNamedParameters));
}
mapperMethod.execute(sqlSession, args)public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
if(){
//.......
} else if (SqlCommandType.SELECT == command.getType()) {
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
} else if (SqlCommandType.FLUSH == command.getType()) {
result = sqlSession.flushStatements();
} else {
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
result = executeForMany(sqlSession, args);private public Object convertArgsToSqlCommandParam(Object[] args) {
final int paramCount = params.size();
if (args == null || paramCount == 0) {
return null;
} else if (!hasNamedParameters && paramCount == 1) {
return args[params.keySet().iterator().next()];
} else {
final Mapresult = sqlSession.public private Object wrapCollection(final Object object) {
//如果是集合
if (object instanceof Collection) {
StrictMap @Override
public ms.getBoundSql(parameter);
@Override
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
if (closed) {
throw new ExecutorException("Executor was closed.");
}
CacheKey cacheKey = new CacheKey();
cacheKey.update(ms.getId());
cacheKey.update(Integer.valueOf(rowBounds.getOffset()));
cacheKey.update(Integer.valueOf(rowBounds.getLimit()));
cacheKey.update(boundSql.getSql());
List
private void doUpdate(Object object) {
int baseHashCode = object == null ? 1 : object.hashCode();
count++;
checksum += baseHashCode;
baseHashCode *= count;
hashcode = multiplier * hashcode + baseHashCode;
updateList.add(object);
}
query@Override
public
@Override
public @Options(flushCache= Options.FlushCachePolicy.TRUE)
private @Override
public public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);
return statementHandler;
}
public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
switch (ms.getStatementType()) {
case STATEMENT:
delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case PREPARED:
delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
case CALLABLE:
delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);
break;
default:
throw new ExecutorException("Unknown statement type: " + ms.getStatementType());
}
}
PreparedStatementHandler private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return stmt;
}
@Override
public Statement prepare(Connection connection) throws SQLException {
Statement statement = null;
statement = instantiateStatement(connection);
//设置超时
setStatementTimeout(statement);
//设置获取数据大小
setFetchSize(statement);
return statement;
//....
}
@Override
protected Statement instantiateStatement(Connection connection) throws SQLException {
String sql = boundSql.getSql();
if (mappedStatement.getKeyGenerator() instanceof Jdbc3KeyGenerator) {
String[] keyColumnNames = mappedStatement.getKeyColumns();
if (keyColumnNames == null) {
return connection.prepareStatement(sql, PreparedStatement.RETURN_GENERATED_KEYS);
} else {
return connection.prepareStatement(sql, keyColumnNames);
}
} else if (mappedStatement.getResultSetType() != null) {
//将会走到这里返回preparedStatement
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareStatement(sql);
}
}
handler.parameterize(stmt);@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List@Override
public void setParameter(PreparedStatement ps, int i, T parameter, JdbcType jdbcType) throws SQLException {
if (parameter == null) {
if (jdbcType == null) {
throw new TypeException("JDBC requires that the JdbcType must be specified for all nullable parameters.");
}
try {
ps.setNull(i, jdbcType.TYPE_CODE);
} catch (SQLException e) {
throw new TypeException("Error setting null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different jdbcTypeForNull configuration property. " +
"Cause: " + e, e);
}
} else {
try {
//进入这里
setNonNullParameter(ps, i, parameter, jdbcType);
} catch (Exception e) {
throw new TypeException("Error setting non null for parameter #" + i + " with JdbcType " + jdbcType + " . " +
"Try setting a different JdbcType for this parameter or a different configuration property. " +
"Cause: " + e, e);
}
}
}
public class IntegerTypeHandler extends BaseTypeHandler@Override
public
登录查看全部
参与评论
手机查看
返回顶部