源码分析环境搭建,我们将从mybatis 的原生api 开始分析,作为分析源码的入口。
1. 环境搭建
github: https://github.com/yoxiyoxiiii/boot-mybatis
2. 查询分析 (mapper.xml 可用逆向工程生成,重点不是这个)
@Test
public void selectOne() throws IOException {
String config = "config.xml";
InputStream inputStream = Resources.getResourceAsStream(config);
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);
SqlSession sqlSession = sqlSessionFactory.openSession();
User user = sqlSession.selectOne("com.example.bootmybatis.dao.UserMapper.selectByPrimaryKey", 1);
System.out.println(user);
sqlSession.close();
}
这里基本上的每句代码都有作用,我们姑且先从第一感觉 selectOne() 这个方法开始。
User user = sqlSession.selectOne("com.example.bootmybatis.dao.UserMapper.selectByPrimaryKey", 1);
sqlSession.selectOne() 方法 两个参数:
第一个:com.example.bootmybatis.dao.UserMapper.selectByPrimaryKey 对应mapper 接口中的方法。
第二个: 表示 查询参数,也就是查询 id = 1 的user 对象。
2.1 sqlSession.selectOne()
public interface SqlSession extends Closeable {
/**
* Retrieve a single row mapped from the statement key.
* @param <T> the returned object type
* @param statement
* @return Mapped object
*/
<T> T selectOne(String statement);
/**
* Retrieve a single row mapped from the statement key and parameter.
* @param <T> the returned object type
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @return Mapped object
*/
<T> T selectOne(String statement, Object parameter);
/**
* Retrieve a list of mapped objects from the statement key and parameter.
* @param <E> the returned list element type
* @param statement Unique identifier matching the statement to use.
* @return List of mapped object
*/
<E> List<E> selectList(String statement);
/**
* Retrieve a list of mapped objects from the statement key and parameter.
* @param <E> the returned list element type
* @param statement Unique identifier matching the statement to use.
* @param parameter A parameter object to pass to the statement.
* @return List of mapped object
*/
<E> List<E> selectList(String statement, Object parameter);
..... 省略其他方法。
}
SqlSession.png点进去我们就会发现 SqlSession 接口申明了 这些方法,我们来看一下接口的实现有哪些:
上图我们sqlSession看到有三个 实现类,那我们在这里用的哪一个呢?最简单的办法就 debug 一下,可以看出来是 DefaultSqlSession ,然后我们就来看看 为什么是 DefaultSqlSession 而不是其他。这里就要从前面几句代码找答案了。
String config = "config.xml";
InputStream inputStream = Resources.getResourceAsStream(config); //这里是读取配置文件
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder()
.build(inputStream);// 这句话就是关键
SqlSession sqlSession = sqlSessionFactory.openSession();
2.2: SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
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);
}
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;
}
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
@Override
public SqlSession openSession(ExecutorType execType) {
return openSessionFromDataSource(execType, null, false);
}
@Override
public SqlSession openSession(TransactionIsolationLevel level) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, TransactionIsolationLevel level) {
return openSessionFromDataSource(execType, level, false);
}
@Override
public SqlSession openSession(ExecutorType execType, boolean autoCommit) {
return openSessionFromDataSource(execType, null, autoCommit);
}
@Override
public SqlSession openSession(Connection connection) {
return openSessionFromConnection(configuration.getDefaultExecutorType(), connection);
}
@Override
public SqlSession openSession(ExecutorType execType, Connection connection) {
return openSessionFromConnection(execType, connection);
}
@Override
public Configuration getConfiguration() {
return configuration;
}
// SqlSession sqlSession = sqlSessionFactory.openSession(); 这句话就会调这里,
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
// 创建 DefaultSqlSession 对象,这里就解释了为什么是DefaultSqlSession 而不是其他的实现类。
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();
}
}
2.3 回到 selectOne 方法。
在知道实现类以后我们就来看一下 DefaultSqlSession 中的 selectOne() 方法:
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many. 复用 selectList()方法。
List<T> list = this.selectList(statement, parameter);
if (list.size() == 1) { //判断集合,返回一条
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
//最后会到这里
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {// 从配置信息里面获取 sql 映射的对象 MappedStatement 暂时可以暴力的理解为 从 mapper.xml 中获取用执行的sql 语句,其实不仅仅是这样的。
// statement = com.example.bootmybatis.dao.UserMapper.selectByPrimaryKey
MappedStatement ms = configuration.getMappedStatement(statement);
// 执行查询,查询动作交给了 executor 对象。
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
executor.query(ms, wrapCollection(parameter) 执行查询,返回结果,后面我们在来分析 executor 的过程。
我们来骚味 总结一下 ,到这里我们都分析出哪些东西:
1:我们知道 sqlSession 具体接口对象 是 DefaultSqlSession
2:具体的 查询任务 sql 语句执行 是 交给了一个 叫 executor 的对象。
3:用到的设计模式:工作模式 SqlSessionFactory
网友评论