1.准备工作
1.1.mybatis.xml
里面做了数据源及mapper的一些配置
<?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>
<property name="name" value="张三" />
</properties>
<settings>
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<environments default="development">
<environment id="development">
<transactionManager type="JDBC" />
<dataSource type="POOLED">
<property name="driver" value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/aaa?serverTimezone=UTC" />
<property name="username" value="root" />
<property name="password" value="123456" />
</dataSource>
</environment>
</environments>
<mappers>
<mapper class="com.test.mybatis.ProjectMapper"></mapper>
</mappers>
</configuration>
1.2.project.mapper
<mapper namespace="com.test.mybatis.ProjectMapper">
<select id="find" parameterType="int" resultType="string">
select name from user where id = #{projectid}
</select>
</mapper>
1.3.mapper.class
package com.test.mybatis;
import org.apache.ibatis.annotations.Param;
public interface ProjectMapper {
String find(@Param("projectid") int id);
}
1.4.一个测试类
public class Test {
public static void main(String[] args) throws IOException {
String resource = "mybatis.xml";
InputStream inputStream = Resources.getResourceAsStream(resource);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession session = sqlSessionFactory.openSession();
try {
Object selectOne = session.selectOne("com.test.mybatis.ProjectMapper.find", 1);
System.out.println(selectOne);
} finally {
session.close();
}
}
}
2.DEBUG模式运行上述代码
2.1通过xml获取SqlSessionFactory,这个是全局唯一的
xml > inputStream //读取xml到inputStream
SqlSessionFactoryBuilder.build //创建SqlSessionFactory,Builder
inputStream > XMLConfigBuilder //将inputstream 包装进XMLConfigBuilder
Configuration = XMLConfigBuilder.parse //要解析成Configuration
parseConfiguration //加载配置文件
propertiesElement(root.evalNode("properties")); // 解析<properties>
<properties>解析进configuration.variables // 放到Configuration里
Properties settings = settingsAsProperties(root.evalNode("settings"));// 解析<settings>
loadCustomVfs(settings);
loadCustomLogImpl(settings);
typeAliasesElement(root.evalNode("typeAliases"));
pluginElement(root.evalNode("plugins"));
objectFactoryElement(root.evalNode("objectFactory"));
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
reflectorFactoryElement(root.evalNode("reflectorFactory"));
settingsElement(settings);
typeHandlerElement(root.evalNode("typeHandlers"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
environmentsElement(root.evalNode("environments"));// 解析<environments>
解析environments标签 // 获取TransactionFactory和datasource
configuration.setEnvironment(datasource,TransactionFactory)// 放到Configuration里
mapperElement(root.evalNode("mappers")); // 解析mappers
configuration.addMapper(MapperClass.class)
if (class is interface){ //如果是个接口
knownMappers.put(type, new MapperProxyFactory<>(type));
MapperAnnotationBuilder.parse();
loadXmlResource();//解析xml //解析对应的mapper.xml
XMLMapperBuilder.parse()
cacheRefElement(context.evalNode("cache-ref")); //解析缓存标签
cacheElement(context.evalNode("cache"));
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
resultMapElements(context.evalNodes("/mapper/resultMap"));
sqlElement(context.evalNodes("/mapper/sql"));
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));//解析select|insert|update|delete标签
XMLStatementBuilder.parseStatementNode();//存储到最终的对象
configuration.addLoadedResource(resource);
assistant.setCurrentNamespace(type.getName());
parseCache();
parseCacheRef();
Method[] methods = type.getMethods();
for (Method method : methods) { //遍历接口的每一个方法,对应出每一个MappedStatement,放到Configuration里
parseStatement(method);
根据注解生成SqlSource
sql = PropertyParser.parse(script,configuration.getVariables())
MappedStatement statement = MappedStatement.Builder.build();//最终的对象
configuration.addMappedStatement(statement);
}
}
2.2通过SqlSessionFactory获取SqlSession,主要是拿到DataSource和事务
SqlSession session = sqlSessionFactory.openSession();
Environment environment = configuration.getEnvironment();
TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
2.3执行selectOne
SqlSession.selectOne
DefaultSqlSession.selectOne
List<T> list = this.selectList(statement, parameter);//查询list,然后获取list.get(0)就是selectOne.
CachingExecutor.query
CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
if (cache){ //如果有缓存,使用缓存
use cache
}else{
//如果没有缓存
SimpleExecutor.query
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql);//包装出了StatementHandler
statementHandler = (StatementHandler) interceptorChain.pluginAll(statementHandler);//interceptor执行
Statement stmt = prepareStatement(handler, ms.getStatementLog());
Connection connection = getConnection(statementLog);//此时会连接数据库生成链接
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
stmt = StatementHandler.prepare(connection, transaction.getTimeout());
PreparedStatementHandler.prepare
statement = instantiateStatement(connection);
statement = connection.prepareStatement(sql)
一顿反射
PreparedStatement stmt = (PreparedStatement) method(prepareStatement).invoke(com.mysql.cj.jdbc.ConnectionImpl, params);//jdbc
PreparedStatementLogger stmt = PreparedStatementLogger.newInstance(stmt, statementLog, queryStack);//动态代理包装
handler.parameterize(stmt); //sql参数设置
PreparedStatementHandler.parameterize(statement);
调用PreparedStatementLogger的设置参数(动态代理)
return handler.query(stmt, resultHandler);
PreparedStatementHandler.query(PreparedStatementLogger, resultHandler)
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();//调用PreparedStatementLogger的execute(动态代理)
return resultSetHandler.handleResultSets(ps);//处理结果集
}
2.4 附上PreparedStatementLogger包装类的源码
package org.apache.ibatis.logging.jdbc;
public final class PreparedStatementLogger extends BaseJdbcLogger implements InvocationHandler {
// 如果是mysql的话,这个真实对象是com.mysql.cj.jdbc.ClientPreparedStatement,属于mysql-connect.jar里的操作数据库的对象了.
private final PreparedStatement statement;
private PreparedStatementLogger(PreparedStatement stmt, Log statementLog, int queryStack) {
super(statementLog, queryStack);
this.statement = stmt;
}
@Override
public Object invoke(Object proxy, Method method, Object[] params) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, params);
}
//EXECUTE_METHODS=[addBatch, execute, executeUpdate, executeQuery]
//EXECUTE_METHODS数组有上述四种方法,这个数组里面都是操作数据库的
if (EXECUTE_METHODS.contains(method.getName())) {
/**
查看当前日志系统是否是debug,如果是debug就打印.如果使用的日志是StdOutImpl就默认是debug
*/
if (isDebugEnabled()) {
debug("Parameters: " + getParameterValueString(), true);
}
clearColumnInfo();
if ("executeQuery".equals(method.getName())) {
ResultSet rs = (ResultSet) method.invoke(statement, params);
return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
} else {
return method.invoke(statement, params);//这个执行的最多
}
} else if (SET_METHODS.contains(method.getName())) {
//SET_METHODS = [setByte, setNull, setShort, setObject, setDouble, setTimestamp, setTime, setBytes,setInt, setURL, setArray, setLong, setString...]
//SET_METHODS 有上述的关于注入参数的一些方法.
if ("setNull".equals(method.getName())) {
setColumn(params[0], null);
} else {
setColumn(params[0], params[1]);
}
return method.invoke(statement, params);
} else if ("getResultSet".equals(method.getName())) {
ResultSet rs = (ResultSet) method.invoke(statement, params);
return rs == null ? null : ResultSetLogger.newInstance(rs, statementLog, queryStack);
} else if ("getUpdateCount".equals(method.getName())) {
int updateCount = (Integer) method.invoke(statement, params);
if (updateCount != -1) {
debug(" Updates: " + updateCount, false);
}
return updateCount;
} else {
return method.invoke(statement, params);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
}
public static PreparedStatement newInstance(PreparedStatement stmt, Log statementLog, int queryStack) {
InvocationHandler handler = new PreparedStatementLogger(stmt, statementLog, queryStack);
ClassLoader cl = PreparedStatement.class.getClassLoader();
return (PreparedStatement) Proxy.newProxyInstance(cl, new Class[]{PreparedStatement.class, CallableStatement.class}, handler);
}
public PreparedStatement getPreparedStatement() {
return statement;
}
}