Mybtais源码(九):增删改执行流程
在Mybatis源码(七):SQL执行流程中已提到,根据不同的sqlCommandType执行不同类型的SQL,下面来看看调用Mapper接口的新增、修改、删除,Mybatis中做了哪些处理。
1、新增
1 // 新增用户 2 User user = new User(); 3 user.setId(105); 4 user.setName("insert"); 5 user.setCreateDate(new Date()); 6 user.setUpdateDate(new Date()); 7 int addUser = mapper.insertUserInfo(user); 8 System.out.println("新增用户结果: " + addUser);
1、创建MapperMethod对象
MapperMethod对象在Mybatis源码(七):SQL执行流程中已做分析,MapperMethod对象持有SqlCommand、MethodSignature对象,新增时MapperMethod对象详情如下:
2、执行新增流程
MapperMethod#execute() 核心代码段:
1 case INSERT: { 2 // 使用ParamNameResolver处理args数组,将用户传入的实参与指定参数名称关联起来 3 Object param = method.convertArgsToSqlCommandParam(args); 4 // 调用sqlSession.insert方法,rowCountResult方法会根据method字段中记录的方法的返回值类型对结果进行转换 5 result = rowCountResult(sqlSession.insert(command.getName(), param)); 6 break; 7 }
2.1、方法参数解析成SQL参数
param详情如下:
2.2、执行新增操作
1 public int update(String statement, Object parameter) { 2 try { 3 dirty = true; 4 MappedStatement ms = configuration.getMappedStatement(statement); 5 return executor.update(ms, wrapCollection(parameter)); 6 } catch (Exception e) { 7 throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); 8 } finally { 9 ErrorContext.instance().reset(); 10 } 11 }
1、获取MappedStatement对象
根据SatementId(接口全限定名 + 方法名) 获取configuration中的MappedStatement对象,MappedStatement对象详情如下:
2、执行新增
CachingExecutor#update() 核心代码
1 public int update(MappedStatement ms, Object parameterObject) throws SQLException { 2 flushCacheIfRequired(ms); 3 return delegate.update(ms, parameterObject); 4 }
刷新缓存,通过事务缓存管理器TransactionalCacheManager的clear()方法完成缓存的刷新工作。继续执行新增操作,BaseExecutor#update() 核心代码
1 public int update(MappedStatement ms, Object parameter) throws SQLException { 2 ErrorContext.instance().resource(ms.getResource()).activity("executing an update").object(ms.getId()); 3 // 判断当前Executor是否已经关闭 4 if (closed) { 5 throw new ExecutorException("Executor was closed."); 6 } 7 // 清除一级缓存 8 clearLocalCache(); 9 // 执行sql语句 10 return doUpdate(ms, parameter); 11 }
在新增操作执行之前,优先清除一级缓存中内容。继续执行新增操作,SimpleExecutor#doUpdate() 核心代码
1 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { 2 Statement stmt = null; 3 try { 4 Configuration configuration = ms.getConfiguration(); 5 // 新建一个StatementHandler 6 // 这里看到ResultHandler传入的是null 7 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); 8 // 准备语句 9 stmt = prepareStatement(handler, ms.getStatementLog()); 10 return handler.update(stmt); 11 } finally { 12 closeStatement(stmt); 13 } 14 }
1、获取StatementHandler对象
SatementHandler作为Mybatis核心四大对象之一,持有其他三大核心对象 parameterHandler参数处理器、resultSetHandler结果集处理器、Executor执行器。
2、生成可执行SQL语句
SatementHandler对象用于创建Statement对象、生成可执行的SQL。创建的Statement对象详情如下:
已经生成可执行的SQL,同时持从数据源中获取的数据库连接connection.
3、执行新增并返回执行结果
目标SQL语句已生成,准备工作都已经完成,接下来要将数据插入数据库,PreparedStatementHandler#update() 核心伪代码
1 public int update(Statement statement) throws SQLException { 2 PreparedStatement ps = (PreparedStatement) statement; 3 // 原生JDBC操作 4 ps.execute(); 5 // 获取执行结果 6 int rows = ps.getUpdateCount(); 7 // ... 8 return rows; 9 }
2、修改
1、创建MapperMethod对象
MapperMethod对象持有SqlCommand、MethodSignature对象,修改时MapperMethod对象详情如下:
2、执行更新流程
MapperMethod#execute() 核心代码段:
1 // 更新 2 case UPDATE: { 3 Object param = method.convertArgsToSqlCommandParam(args); 4 result = rowCountResult(sqlSession.update(command.getName(), param)); 5 break; 6 }
2.1、方法参数解析成SQL参数
param详情如下:
2.2、执行更新操作
1 public int update(String statement, Object parameter) { 2 try { 3 dirty = true; 4 MappedStatement ms = configuration.getMappedStatement(statement); 5 return executor.update(ms, wrapCollection(parameter)); 6 } catch (Exception e) { 7 throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); 8 } finally { 9 ErrorContext.instance().reset(); 10 } 11 }
1、获取MappedStatement对象
MappedStatement详情如下:
更新与新增流程一样,在执行更新操作之前,优先刷新缓存信息,此处不再赘述流程,可参考新增中的刷新缓存代码逻辑。
2、执行更新操作
SimpleExecutor#doUpdate() 核心代码
1 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { 2 Statement stmt = null; 3 try { 4 Configuration configuration = ms.getConfiguration(); 5 // 新建一个StatementHandler 6 // 这里看到ResultHandler传入的是null 7 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); 8 // 准备语句 9 stmt = prepareStatement(handler, ms.getStatementLog()); 10 // 执行更新 11 return handler.update(stmt); 12 } finally { 13 closeStatement(stmt); 14 } 15 }
1、获取StatementHandler对象
2、创建PreparedStatement对象,SQL参数解析生成可执行SQL语句
3、执行更新并返回执行结果
1 public int update(Statement statement) throws SQLException { 2 PreparedStatement ps = (PreparedStatement) statement; 3 ps.execute(); 4 int rows = ps.getUpdateCount(); 5 // ... 6 return rows; 7 }
3、删除
1、创建MapperMethod对象
MapperMethod对象持有SqlCommand、MethodSignature对象,删除时MapperMethod对象详情如下:
2、执行删除流程
1 // 删除 2 case DELETE: { 3 Object param = method.convertArgsToSqlCommandParam(args); 4 result = rowCountResult(sqlSession.delete(command.getName(), param)); 5 break; 6 }
2.1、方法参数解析成SQL参数
param详情如下:
2.2、执行删除操作
1 public int update(String statement, Object parameter) { 2 try { 3 dirty = true; 4 MappedStatement ms = configuration.getMappedStatement(statement); 5 return executor.update(ms, wrapCollection(parameter)); 6 } catch (Exception e) { 7 throw ExceptionFactory.wrapException("Error updating database. Cause: " + e, e); 8 } finally { 9 ErrorContext.instance().reset(); 10 } 11 }
1、获取MappedStatement对象
MappedStatement详情如下:
2、执行删除
SimpleExecutor#doUpdate() 核心代码
1 public int doUpdate(MappedStatement ms, Object parameter) throws SQLException { 2 Statement stmt = null; 3 try { 4 Configuration configuration = ms.getConfiguration(); 5 // 新建一个StatementHandler 6 // 这里看到ResultHandler传入的是null 7 StatementHandler handler = configuration.newStatementHandler(this, ms, parameter, RowBounds.DEFAULT, null, null); 8 // 准备语句 9 stmt = prepareStatement(handler, ms.getStatementLog()); 10 return handler.update(stmt); 11 } finally { 12 closeStatement(stmt); 13 } 14 }
1、获取StatementHandler对象
2、创建PreparedStatement对象,SQL参数解析生成可执行SQL语句
3、执行更新并返回执行结果
1 public int update(Statement statement) throws SQLException { 2 PreparedStatement ps = (PreparedStatement) statement; 3 ps.execute(); 4 int rows = ps.getUpdateCount(); 5 // ... 6 return rows; 7 }
4、总结
Mybtais中增删改执行的是一套流程,只不过对象MappedStatement、Statemnt中的某些属性不同,比如BoundSql、StatementId等,生成的目标执行sql不同,核心对象的创建是一样。
1、创建MapperMethod对象
创建MapperMethod对象,包含SQL相关信息(接口全限定名+方法名 -> statementId、sql语句类型)、接口方法信息(返回标识、返回类型、参数名称解析器);
2、获取MappedMethod信息
根据接口全限定名+方法名,获取configuraton中的MappedMethod信息,包含StatementType类型,默认为PREPARED;
3、刷新缓存信息
4、Statement对象获取
创建StatementHandler对象,在初始化StatementHandler对象时,创建参数处理器ParameterHandelr、结果集处理器resultSetHandler。
StatementHandler的作用:用于创建statement对象、解析SQL中的占位符,生成可执行SQL。
statement对象:持有数据库连接、可执行SQL
5、执行SQL语句
使用PreparedStatement的execute方法执行SQL,原JDBC流程;
6、结果集的处理。