mybatis
参考:
https://blog.csdn.net/liming363873117/article/details/60467107
https://blog.csdn.net/u014297148/article/details/78696096
采用先代码块再解释的书写方式,比较混乱,暂时记一下,以后再整理。
Mybatis有以下几种组件:
SqlSessionFactory
SqlSessionFactoryBuilder
Configuration
SqlSession
https://img-blog.csdn.net/20171202215246419?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI5NzE0OA==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast
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);
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);
}
Mybatis通过SqlSessionFactoryBuilder来构建SQLSessionFactory,在builder方法中传入配置文件的inputstream,然后会调用XMLConfigBuilder解析这个inputstream,封装都一个configuration对象里面,之后调用重载的参数是configuration的build方法new一个DefaultSqlSessionFactory对象,Configuration对象是对mybatis-config.xml配置文件的封装。也就是通过配置文件来构造一个SQLSessionFactory。
[图片上传失败...(image-94bfca-1539015708192)]
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
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);
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();
}
}
然后通过这个SQLSessionFactory的opensession来打开一个sqlsession,这个SQLSession就相当于jdbc编程的时候的那个connection对象,指一次数据库的会话。返回的是DefaultSession,此时这个SQLSession里面包含一个Configuration和一个Executor对象。
[图片上传失败...(image-a4b3cc-1539015708192)]
DefaultSqlSession.java
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
Configuration.java
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
MapperRegistry.java
@SuppressWarnings("unchecked")
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
之后通过java的动态代理,生成Mapper的代理类MapperProxy。需要传入 getMapper(Class<T> type),也就是接口名称。会在启动的时候生成所有的代理类。
下面进入SQL的执行阶段。
在这一块有四大对象
1、 Executor 执行器
2、 StatementHandler 数据库会话处理器,核心,起承上启下的作用
3、 ParameterHandler 参数处理器
4、 ResultSetHandler 结果处理器
有三种Executor,SimpleExecutor(默认),ReuseExecutor,BatchExecutor。Executor会调度StatementHandler、ParameterHandler、ResultHandler等来执行对应的SQL。
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//判断是否有一级缓存
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
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 if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
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;
}
调用方法的时候实际上是在执行MapperProxy的invoke方法,就是在调用对象代理类的invoke方法,在这个invoke方法里面,先判断一下method是不是Object的toString()等方法
(if (Object.class.equals(method.getDeclaringClass()))),
如果不是则调用mapperMethod.execute(sqlSession, args);方法。在这个方法里面有一个switch判断是那种类型的SQL,select,update,delete等,然后调用sqlsession中对应的方法执行。
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
//从configuration中拿出SQL语句
MappedStatement ms = configuration.getMappedStatement(statement);
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();
}
}
微信截图_20181009000029.png
@Override
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
stmt = handler.prepare(connection, transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
/此处调用原生sql的处理器
PreparedStatement ps = (PreparedStatement) statement;
//发出原生sql命令
ps.execute();
//采用ResultHandler结果处理器对结果集封装
return resultSetHandler.<E> handleResultSets(ps);
}
在这一步会从configuration中根据调用的方法名定位对应的SQL,MappedStatement对象。然后调用Executor对应的方法。之后会在Executor中通过configuration拿到一个StatementHandler,在prepareSatement方法中代用prepare方法提取出SQL语句,然后调用parameterize方法,通过ParameterHandler把参数设置进去。之后调用JDBC原生的SQL处理器处理SQL语句,然后对结果使用ResultHandler进行封装。