Mybatis 源码之更新数据库

流程图

https://www.processon.com/view/link/655098457b996f7b645b6afe

更新

定位: org.apache.ibatis.session.defaults.DefaultSqlSession#update

1
2
3
4
5
6
7
8
9
10
11
12
13
public int update(String statement, Object parameter) {
try {
//每次要更新之前,dirty标志设为true
dirty = true;
MappedStatement ms = configuration.getMappedStatement(statement);
// 用执行器来update结果
return executor.update(ms, wrapCollection(parameter));
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}

org.apache.ibatis.executor.CachingExecutor#update

1
2
3
4
5
public int update(MappedStatement ms, Object parameterObject) throws SQLException {  
// 刷新二级缓存完再 update
flushCacheIfRequired(ms);
return delegate.update(ms, parameterObject);
}

org.apache.ibatis.executor.BaseExecutor#update

1
2
3
4
5
6
7
8
9
10
11
12
// SqlSession.update/insert/delete 都会调用此方法
public int update(MappedStatement ms, Object parameter) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId());
// 判断当前Executor是否已经关闭
if (closed) {
throw new ExecutorException("Executor was closed.");
}
// 先清局部缓存(一级缓存),再更新,如何更新交由子类,模板方法模式
clearLocalCache();
// 执行sql语句
return doUpdate(ms, parameter);
}

org.apache.ibatis.executor.SimpleExecutor#doUpdate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public int doUpdate(MappedStatement ms, Object parameter) throws SQLException {
Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
// 新建一个 StatementHandler
// 这里看到 ResultHandler 传入的是 null
StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null);
// 准备语句
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.update(stmt);
} finally {
closeStatement(stmt);
}
}

org.apache.ibatis.executor.statement.PreparedStatementHandler#update

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public int update(Statement statement) throws SQLException {
PreparedStatement ps = (PreparedStatement) statement;
// 调用 PreparedStatement.execute
ps.execute();
// 调用 PreparedStatement.getUpdateCount
int rows = ps.getUpdateCount();
// 获取实际入参
Object parameterObject = boundSql.getParameterObject();
// 若配置了 useGeneratedKeys 并且是 insert 语句,
// 则返回 Jdbc3KeyGenerator.INSTANCE, 否则返回 NoKeyGenerator.INSTANCE
// 若配置了 sekectKey, 则使用 SelectKeyGenerator 的实例
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
// 执行主键生成器的后置方法, 主要给入参设置对应的主键值
keyGenerator.processAfter(executor, mappedStatement, ps, parameterObject);
// 返回更新的行数
return rows;
}

插入

org.apache.ibatis.session.defaults.DefaultSqlSession#insert

1
2
3
4
5
6
7
8
9
@Override
public int insert(String statement) {
return insert(statement, null);
}
@Override
public int insert(String statement, Object parameter) {
// 调用更新
return update(statement, parameter);
}

PreparedStatementHandler 更新

定位: org.apache.ibatis.executor.statement.BaseStatementHandler#BaseStatementHandler

作用: 语句处理器的基类, 其子类有PreparedStatementHandler, SimpleStatementHandler, CallableStatementHandler

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
protected BaseStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {
// 初始化字段
this.configuration = mappedStatement.getConfiguration();
this.executor = executor;
this.mappedStatement = mappedStatement;
this.rowBounds = rowBounds;

this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();
this.objectFactory = configuration.getObjectFactory();

if (boundSql == null) { // issue #435, get the key before calculating the statement
// 调用 KeyGenerator.processBefore方法获取主键
generateKeys(parameterObject);
boundSql = mappedStatement.getBoundSql(parameterObject);
}

this.boundSql = boundSql;
// 生成 parameterHandler
this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);
// 生成 resultSetHandler
this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);
}
// 生成 key
protected void generateKeys(Object parameter) {
KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();
ErrorContext.instance().store();
// 调用主键生成器的前置方法
keyGenerator.processBefore(executor, mappedStatement, null, parameter);
ErrorContext.instance().recall();
}

org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator

主键生成器, 默认使用数据库的生成策略, 将生成后的主键赋值到入参对应的字段中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
@Override
public void processBefore(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// do nothing
}
@Override
public void processAfter(Executor executor, MappedStatement ms, Statement stmt, Object parameter) {
// 将用户传入的实参 parameter 封装成集合类型,然后传入 processBatch 方法中处理
processBatch(ms, stmt, parameter);
}
public void processBatch(MappedStatement ms, Statement stmt, Object parameter) {
// 获取 keyProperties 属性指定的属性名称,它表示主键对应的属性名称
final String[] keyProperties = ms.getKeyProperties();
if (keyProperties == null || keyProperties.length == 0) {
return;
}
// 核心是使用 JDBC3 的 Statement.getGeneratedKeys
try (ResultSet rs = stmt.getGeneratedKeys()) {
// 获取ResultSet的元数据信息
final ResultSetMetaData rsmd = rs.getMetaData();
final Configuration configuration = ms.getConfiguration();
// 检测数据库生成的主键的列数与 keyProperties 属性指定的列数是否匹配
if (rsmd.getColumnCount() < keyProperties.length) {
// Error?
} else {
// 主键列的值赋值到入参对象中
assignKeys(configuration, rs, rsmd, keyProperties, parameter);
}
} catch (Exception e) {
throw new ExecutorException("Error getting generated key or setting result to parameter object. Cause: " + e, e);
}
}

删除

org.apache.ibatis.session.defaults.DefaultSqlSession#delete

1
2
3
4
5
6
7
8
9
@Override
public int delete(String statement) {
return update(statement, null);
}
@Override
public int delete(String statement, Object parameter) {
// delete 也是调用更新
return update(statement, parameter);
}