您的位置:首页 > 数据库

MyBatis的Sql执行过程源码解读

2015-04-03 14:19 447 查看
1.先获得SqlSessionFactory

通过SqlSessionFactoryBuilder去读取mybatis的配置文件,然后build一个DefaultSqlSessionFactory。

/**
* 一系列的构造方法最终都会调用本方法(配置文件为Reader时会调用本方法,还有一个InputStream方法与此对应)
* @param reader
* @param environment
* @param properties
* @return
*/
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
//通过XMLConfigBuilder解析配置文件,解析的配置相关信息都会封装为一个Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
//这儿创建DefaultSessionFactory对象
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(Configuration config) {
return new DefaultSqlSessionFactory(config);
}


2.通过SqlSessionFactory去获取SqlSession对象
public SqlSession openSession()
{
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit)
{
Transaction tx = null;
try
{
//通过Configuration对象去获取相关的配置信息,Environment对象包含了数据源和事务的配置
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//实际上就是Executor来执行sql语句,executor是对于Statement的封装
final Executor executor = configuration.newExecutor(tx, execType, autoCommit);
//创建DefaultSqlSession对象
return new DefaultSqlSession(configuration, executor);
}
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();
}
}
这样就获得了SqlSession对象

3.通过SqlSession获得Mapper

public <T> T getMapper(Class<T> type)
{
return configuration.<T>getMapper(type, this);
}
这里通过Configuration的getMapper方法来获得

public <T> T getMapper(Class<T> type, SqlSession sqlSession)
{
return mapperRegistry.getMapper(type, sqlSession);
}
protected MapperRegistry mapperRegistry = new MapperRegistry(this);


继续看MapperRegistry的getMapper方法

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);   //此处使用反射,生成一个MapperProxyFactory对象
}
catch (Exception e)
{
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px; background-color: rgb(255, 255, 255);">            </span>


knownMappers在读取配置文件的时候,已经将mapper信息放入其中了。

继续看MapperProxyFactory的newInstance方法:

protected T newInstance(MapperProxy<T> mapperProxy)
{
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}

public T newInstance(SqlSession sqlSession)
{
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
MapperProxy就是一个代理类,使用的是jdk的动态代理

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
{
if (Object.class.equals(method.getDeclaringClass()))
{
return method.invoke(this, args);
}
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
这里的invoke方法可以明确看出使用的是jdk的动态代理

这样的话就会返回一个mapper的代理类,每次执行的时候,回交给MapperMethod类的execute方法

public Object execute(SqlSession sqlSession, Object[] args)
{
Object result;
if (SqlCommandType.INSERT == command.getType())
{
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
}
else if (SqlCommandType.UPDATE == command.getType())
{
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
}
else if (SqlCommandType.DELETE == command.getType())
{
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
}
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
{
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;
}
可以看出,也就是判断一下CURD的类型,然后实际调用的还是SqlSession 的方法,在这里以selectList为例

public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);
List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
return result;
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
继续查找Executor的query方法,在这里使用BaseExecutor的

public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException
{
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
继续查找到SimpleExecutor的doQuery,可以看到

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(this, 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);
handler.parameterize(stmt);
return stmt;
}
可以看出实际上也就好似调用的jdbc
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: