Mybatis原始碼解析之寫流程
阿新 • • 發佈:2019-02-08
閱讀須知
- Mybatis原始碼版本:3.4.4
- 註釋規則:
- //單行註釋做普通註釋
- /**/多行註釋做深入分析
- 建議配合Mybatis原始碼閱讀
正文
承接上文,我們繼續來分析寫操作:
DefaultSqlSession:
public int insert(String statement, Object parameter) {
return update(statement, parameter);
}
DefaultSqlSession:
public int update(String statement, Object parameter) {
try {
dirty = true;
//獲取MappedStatement
MappedStatement ms = configuration.getMappedStatement(statement);
/*包裝集合型別的引數(分析查詢流程時已經分析過),執行更新操作*/
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
DefaultSqlSession:
public int delete(String statement, Object parameter) {
return update(statement, parameter);
}
我們發現insert、update、delete三個方法最終都呼叫了同一個update方法。
CachingExecutor:
public int update(MappedStatement ms, Object parameterObject) throws SQLException {
flushCacheIfRequired(ms); //如果需要,重新整理快取
/*更新操作*/
return delegate.update(ms, parameterObject);
}
Mybatis快取我們會用單獨的文章來分析。
BaseExecutor:
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
if (closed) {
throw new ExecutorException("Executor was closed.");
}
clearLocalCache(); //清除本地快取
return doUpdate(ms, parameter); /*執行更新操作*/
}
SimpleExecutor:
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
//建立StatementHandler(分析查詢流程時已經分析過)
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
//準備Statement(分析查詢流程時已經分析過)
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt); /*更新操作*/
} finally {
closeStatement(stmt); //關閉Statement
}
}
PreparedStatementHandler:
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
ps.execute(); //執行sql命令
int rows = ps.getUpdateCount(); //返回影響的行數
Object parameterObject = boundSql.getParameterObject();
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
/*KeyGenerator後置處理(前置處理在建立StatementHandler時應用)*/
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
return rows;
}
我們以SelectKeyGenerator來分析KeyGenerator的後置處理:
SelectKeyGenerator:
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
if (!executeBefore) { //如果不是前置處理
/*處理生成的key*/
processGeneratedKeys(executor, ms, parameter);
}
}
分析之前我們可以先回想一下<selectkey/>
標籤的應用,有助於理解下面的處理過程。
SelectKeyGenerator:
private void processGeneratedKeys(Executor executor, MappedStatement ms, Object parameter) {
try {
if (parameter != null && keyStatement != null && keyStatement.getKeyProperties() != null) {
String[] keyProperties = keyStatement.getKeyProperties(); //獲取配置的目標屬性
final Configuration configuration = ms.getConfiguration();
final MetaObject metaParam = configuration.newMetaObject(parameter);
if (keyProperties != null) {
//新建執行器
Executor keyExecutor = configuration.newExecutor(executor.getTransaction(), ExecutorType.SIMPLE);
//執行查詢
List<Object> values = keyExecutor.query(keyStatement, parameter, RowBounds.DEFAULT, Executor.NO_RESULT_HANDLER);
//返回結果集長度的校驗
if (values.size() == 0) {
throw new ExecutorException("SelectKey returned no data.");
} else if (values.size() > 1) {
throw new ExecutorException("SelectKey returned more than one value.");
} else {
MetaObject metaResult = configuration.newMetaObject(values.get(0));
//如果只設置了單個目標屬性直接賦值
if (keyProperties.length == 1) {
if (metaResult.hasGetter(keyProperties[0])) {
setValue(metaParam, keyProperties[0], metaResult.getValue(keyProperties[0]));
} else {
setValue(metaParam, keyProperties[0], values.get(0));
}
} else {
/*設定多個目標屬性的處理*/
handleMultipleProperties(keyProperties, metaParam, metaResult);
}
}
}
}
} catch (ExecutorException e) {
throw e;
} catch (Exception e) {
throw new ExecutorException("Error selecting key or setting result to parameter object. Cause: " + e, e);
}
}
SelectKeyGenerator:
private void handleMultipleProperties(String[] keyProperties,
MetaObject metaParam, MetaObject metaResult) {
String[] keyColumns = keyStatement.getKeyColumns();
if (keyColumns == null || keyColumns.length == 0) {
//沒有指定具體的列,直接使用屬性名稱賦值
for (String keyProperty : keyProperties) {
setValue(metaParam, keyProperty, metaResult.getValue(keyProperty));
}
} else {
//指定列的數量與屬性的數量不相等丟擲異常
if (keyColumns.length != keyProperties.length) {
throw new ExecutorException("If SelectKey has key columns, the number must match the number of key properties.");
}
for (int i = 0; i < keyProperties.length; i++) {
//使用列名賦值
setValue(metaParam, keyProperties[i], metaResult.getValue(keyColumns[i]));
}
}
}
最後是對返回影響行數的處理:
private Object rowCountResult(int rowCount) {
final Object result;
//根據方法返回值型別將影響行數轉換成對應的型別
if (method.returnsVoid()) {
result = null;
} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
result = rowCount;
} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
result = (long)rowCount;
} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
result = rowCount > 0;
} else {
throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
}
return result;
}
到這裡,Mybatis寫操作的原始碼分析就完成了。