在之前已經(jīng)看過Executor和MappedStatement
mybatis筆記-Executor
mybatis筆記-MappedStatement
接下來繼續(xù)分析其內(nèi)部的流程.
1.SimpleExecutor的doQuery方法
可以看到內(nèi)部執(zhí)行的流程是由StatementHandler完成的,實(shí)際Executor并沒有真正執(zhí)行sql語句,所以我們要把關(guān)注點(diǎn)轉(zhuǎn)移到StatementHandler
@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);
}
}
2.jdbc原生查詢
public static List<Map<String,Object>> queryForList(){
Connection connection = null;
ResultSet rs = null;
PreparedStatement stmt = null;
List<Map<String,Object>> resultList = new ArrayList<Map<String,Object>>();
try {
// 加載JDBC驅(qū)動
Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
String url = "jdbc:oracle:thin:@localhost:1521:ORACLEDB";
String user = "trainer";
String password = "trainer";
// 獲取數(shù)據(jù)庫連接
connection = DriverManager.getConnection(url,user,password);
String sql = "select * from userinfo where user_id = ? ";
// 創(chuàng)建Statement對象(每一個Statement為一次數(shù)據(jù)庫執(zhí)行請求)
stmt = connection.prepareStatement(sql);
// 設(shè)置傳入?yún)?shù)
stmt.setString(1, "zhangsan");
// 執(zhí)行SQL語句
rs = stmt.executeQuery();
// 處理查詢結(jié)果(將查詢結(jié)果轉(zhuǎn)換成List<Map>格式)
ResultSetMetaData rsmd = rs.getMetaData();
int num = rsmd.getColumnCount();
while(rs.next()){
Map map = new HashMap();
for(int i = 0;i < num;i++){
String columnName = rsmd.getColumnName(i+1);
map.put(columnName,rs.getString(columnName));
}
resultList.add(map);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
// 關(guān)閉結(jié)果集
if (rs != null) {
rs.close();
rs = null;
}
// 關(guān)閉執(zhí)行
if (stmt != null) {
stmt.close();
stmt = null;
}
if (connection != null) {
connection.close();
connection = null;
}
} catch (SQLException e) {
e.printStackTrace();
}
}
return resultList;
}
對比上面流程,Executor在doQuery方法中準(zhǔn)備了BoundSql,接下來還需要一下流程
- 獲取Connection
- 創(chuàng)建PreparedStatement
- 填充sql參數(shù)
- 執(zhí)行sql語句
- 處理查詢結(jié)果集
下來就把上面的流程走一遍
3.獲取Connection
由BaseExecutor方法提供準(zhǔn)備
protected Connection getConnection(Log statementLog) throws SQLException {
Connection connection = transaction.getConnection();
if (statementLog.isDebugEnabled()) {
return ConnectionLogger.newInstance(connection, statementLog, queryStack);
} else {
return connection;
}
}
4.創(chuàng)建PreparedStatement
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;
}
這部分流程是由StatementHandler的prepare方法和parameterize完成的
- prepare做了初始化
- parameterize做了參數(shù)話數(shù)據(jù)填充的工作
@Override
public Statement prepare(Connection connection, Integer transactionTimeout)
throws SQLException {
ErrorContext.instance().sql(boundSql.getSql());
Statement statement = null;
try {
statement = instantiateStatement(connection);
setStatementTimeout(statement, transactionTimeout);
setFetchSize(statement);
return statement;
} catch (SQLException e) {
closeStatement(statement);
throw e;
} catch (Exception e) {
closeStatement(statement);
throw new ExecutorException("Error preparing statement. Cause: " + e, e);
}
}
protected abstract Statement instantiateStatement(Connection connection) throws SQLException;
PreparedStatementHandler的instantiateStatement實(shí)現(xiàn),
connection.prepareStatement方法需要傳入sql語句,所以這里用到了boundSql
@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) {
return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(),
ResultSet.CONCUR_READ_ONLY);
} else {
return connection.prepareStatement(sql);
}
}
5.填充sql參數(shù)
parameterize方法調(diào)用了ParameterHandler的setParameters方法
@Override
public void parameterize(Statement statement) throws SQLException {
parameterHandler.setParameters((PreparedStatement) statement);
}
結(jié)合了BoundSql的ParameterMapping和MappedStatement的parameterObject獲取需要設(shè)置的參數(shù),再結(jié)合TypeHandler再做數(shù)據(jù)轉(zhuǎn)換為PreparedStatement填充參數(shù)
@Override
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings != null) {
for (int i = 0; i < parameterMappings.size(); i++) {
ParameterMapping parameterMapping = parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
Object value;
String propertyName = parameterMapping.getProperty();
if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
value = boundSql.getAdditionalParameter(propertyName);
} else if (parameterObject == null) {
value = null;
} else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
value = parameterObject;
} else {
MetaObject metaObject = configuration.newMetaObject(parameterObject);
value = metaObject.getValue(propertyName);
}
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
} catch (SQLException e) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
}
}
}
}
}
6. 執(zhí)行sql語句
調(diào)用PreparedStatement的execute方法
@Override
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute();
return resultSetHandler.<E> handleResultSets(ps);
}
7.處理查詢結(jié)果集
如上代碼,結(jié)果集由ResultSetHandler處理
整體思路是抓住jdbc原生流程去對照分析
參考:
http://www.reibang.com/p/ec40a82cae28
https://blog.csdn.net/luanlouis/article/details/40422941