1、StatementHandler

StatementHandler接口定义包含创建Statement, 绑定参数,批量执行,更新,查询,获取参数处理器

类结构图为

PreparedStatementHandler用于处理带有占位符的语句

SimpleStatementHandler处理不带占位符的

CallableStatementHandler处理存储过程调用语句

1.1、RoutingStatementHandler

起代理作用,根据不同的语句类型创建不同BaseStatementHandler子类。

public RoutingStatementHandler(Executor executor, MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) {switch (ms.getStatementType()) {case STATEMENT:delegate = new SimpleStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;case PREPARED:delegate = new PreparedStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;case CALLABLE:delegate = new CallableStatementHandler(executor, ms, parameter, rowBounds, resultHandler, boundSql);break;default:throw new ExecutorException("Unknown statement type: " + ms.getStatementType());}}

1.2、BaseStatementHandler

是其它子类的基类,会创建ParameterHandler,ResultSetHandler。BaseStatementHandler依赖两个组件ParameterHandler和ResultSetHandler。

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 statementgenerateKeys(parameterObject);boundSql = mappedStatement.getBoundSql(parameterObject);}this.boundSql = boundSql;this.parameterHandler = configuration.newParameterHandler(mappedStatement, parameterObject, boundSql);this.resultSetHandler = configuration.newResultSetHandler(executor, mappedStatement, rowBounds, parameterHandler, resultHandler, boundSql);}

实现StatementHandlere接口中的prepare,首先调用instantiateStatement抽象方法初始化java.sql.Statement对象,配置超时时间和fetchSize。

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);}}

1.3、SimpleStatementHandler

继承BaseStatementHandler抽象类,sql语句中没有占位符,相应的parameterize方法为空实现。

instantiateStatement直接通过JDBC Connection创建Statemtn对象。

protected Statement instantiateStatement(Connection connection) throws SQLException {if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {return connection.createStatement();} else {return connection.createStatement(mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);}}

查询query 通过创建的Statement对象来完成数据库查询操作,结果通过ResultSetHandler将结果集映射成结果对象。

public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {String sql = boundSql.getSql();statement.execute(sql);return resultSetHandler.handleResultSets(statement);}

queryCursor,batch方法与query方法类似。也是直接调用Statement对象的对应方法。

update方法执行insert、update或delete等sql语句,并且会根据配置的KeyGenerator获取数据库的主键。

public int update(Statement statement) throws SQLException {String sql = boundSql.getSql();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();int rows;if (keyGenerator instanceof Jdbc3KeyGenerator) {statement.execute(sql, Statement.RETURN_GENERATED_KEYS);rows = statement.getUpdateCount();keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else if (keyGenerator instanceof SelectKeyGenerator) {statement.execute(sql);rows = statement.getUpdateCount();keyGenerator.processAfter(executor, mappedStatement, statement, parameterObject);} else {statement.execute(sql);rows = statement.getUpdateCount();}return rows;}

1.4、PreparedStatementHandler

依赖java.sql.PreparedStatement对象来完成数据库的相关操作。

parameterize方法会调用ParameterHandler.setParameters完成sql语句的参数绑定。

instantiateStatement方法会直接调用JDBC Connection的prepareStatement方法创建PreparedStatement对象。

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() == ResultSetType.DEFAULT) {return connection.prepareStatement(sql);} else {return connection.prepareStatement(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);}}

1.5、CallableStatementHandler

依赖于java.sql.CallableStatement调用指定的存储过程,其parameterize方法会调用ParameterHandler.setParameter方法完成sql语句的参数绑定,并指定输出参数的索引位置和JDBC类型。

public void parameterize(Statement statement) throws SQLException {registerOutputParameters((CallableStatement) statement);parameterHandler.setParameters((CallableStatement) statement);}private void registerOutputParameters(CallableStatement cs) throws SQLException {List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();for (int i = 0, n = parameterMappings.size(); i < n; i++) {ParameterMapping parameterMapping = parameterMappings.get(i);if (parameterMapping.getMode() == ParameterMode.OUT || parameterMapping.getMode() == ParameterMode.INOUT) {if (null == parameterMapping.getJdbcType()) {throw new ExecutorException("The JDBC Type must be specified for output parameter.  Parameter: " + parameterMapping.getProperty());} else {if (parameterMapping.getNumericScale() != null && (parameterMapping.getJdbcType() == JdbcType.NUMERIC || parameterMapping.getJdbcType() == JdbcType.DECIMAL)) {cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getNumericScale());} else {if (parameterMapping.getJdbcTypeName() == null) {cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE);} else {cs.registerOutParameter(i + 1, parameterMapping.getJdbcType().TYPE_CODE, parameterMapping.getJdbcTypeName());}}}}}}

instantiateStatement直接调用JDBC Connection的prepareCall创建CallableStatement对象。

protected Statement instantiateStatement(Connection connection) throws SQLException {String sql = boundSql.getSql();if (mappedStatement.getResultSetType() == ResultSetType.DEFAULT) {return connection.prepareCall(sql);} else {return connection.prepareCall(sql, mappedStatement.getResultSetType().getValue(), ResultSet.CONCUR_READ_ONLY);}}

其它方法与以上有一些差异,就是会调用ResultSetHandler的handleOutputParameters处理输出参数

public int update(Statement statement) throws SQLException {CallableStatement cs = (CallableStatement) statement;cs.execute();int rows = cs.getUpdateCount();Object parameterObject = boundSql.getParameterObject();KeyGenerator keyGenerator = mappedStatement.getKeyGenerator();keyGenerator.processAfter(executor, mappedStatement, cs, parameterObject);resultSetHandler.handleOutputParameters(cs);return rows;}public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {CallableStatement cs = (CallableStatement) statement;cs.execute();List<E> resultList = resultSetHandler.handleResultSets(cs);resultSetHandler.handleOutputParameters(cs);return resultList;}public <E> Cursor<E> queryCursor(Statement statement) throws SQLException {CallableStatement cs = (CallableStatement) statement;cs.execute();Cursor<E> resultList = resultSetHandler.handleCursorResultSets(cs);resultSetHandler.handleOutputParameters(cs);return resultList;}

2、ParameterHandler

主要包含绑定参数,及获取参数对象。

DefaultParameterHandler是唯一实现。

绑定参数时,遍历boundSql中的参数映射,忽略输出类型参数。提取值基于以下规则

  1. 属性名是否在boundSql中的附加参数中,如果有,则直接从map中取值。
  2. 参数对象为空时,值设置为null
  3. TypeHandlerRegistry中是否参参数对象所必类型的处理器,有则直接取参数对象(说明是基础类型)
  4. 基于MetaObject获取属性值。

使用TypeHandler来设置PreparementStatement对应的值。

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 paramsvalue = 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 | SQLException e) {throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);}}}}}

mybatis中statementHandler的设计与实现相关推荐

  1. mybatis中ResultSetHandler的设计与实现

    ResultSetHandler主要处理statement,cursor,callstatement三种类型的结果集,其接口定义如下: public interface ResultSetHandle ...

  2. mybatis中 Executor的设计与实现

    Executor的接口定义主要包含sql操作,事务.缓存操作 其基于模板方法模式设计的 其类层次关系图为 1.Executor 1.1 BaseExecutor 是SimpleExecutor,Reu ...

  3. mybatis中的mapper设计与原理

    mapper是基于动态代理来设计的,其类图如下 在MapperRegistry添加mapper时,会基于注解作解析 public <T> void addMapper(Class<T ...

  4. mybatis中sqlSession的设计与实现

    sqlSession基于工厂方法来实现的,SqlSession和SqlSessionFactory的接口定义如下 public interface SqlSession extends Closeab ...

  5. mybatis中缓存的设计与原理

    缓存是基于装饰器设计模式来设计的,接口为Cache,实现类为PerpetualCache,具体的装饰器有基于淘汰策略的.对象引用类型的.序列化的.事务的.同步的.日志的(记录缓存命中率).时间调度的. ...

  6. mybatis中的TypeHandler设计与实现

    TypeHandler主要是用在从java数据写入数据库时,从数据库中读取数据时的从java到jdbc类型之间的转换. 其类层次图为 TypeHandler:主要定义了设置参数.根据列名获取参数,列索 ...

  7. MyBatis 中的九种设计模式

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | http://www.crazyant.net ...

  8. Mybatis系列2:模板模式在Mybatis中的执行器中的应用

    1.什么是模板模式 模板方法模式定义了一个操作中的算法骨架,主要就是抽象方法,将某些步骤延迟到子类中实现,这样新的子类可以在不改变一个算法结构的前提下重新定义该算法的某些特定步骤. 核心: 处理某个流 ...

  9. 聊聊 MyBatis 中的设计模式

    虽然我们都知道有26个设计模式,但是大多停留在概念层面,真实开发中很少遇到,Mybatis源码中使用了大量的设计模式,阅读源码并观察设计模式在其中的应用,能够更深入的理解设计模式. Mybatis至少 ...

最新文章

  1. Idea--使用Idea调试设置
  2. js复制功能的有效方法总结新
  3. 社交游戏纳入文化部监管视野 开发者或出海
  4. mongodb单表最大记录数_SpringBoot+Cloud全家桶微服务实战项目之文档型数据库MongoDB四...
  5. 基于gulp编写的一个简单实用的前端开发环境
  6. [多线程] Thread
  7. java四类八种_java四类八种基本数据类型
  8. python时间段_python--时间段遍历
  9. 人与人之间需要最基本的信任
  10. ocr 哪个好 外文_5 款堪称神器的高质量软件,每一款都好用到不想卸载
  11. 屏蔽Codeforces做题时的Problem tags提示
  12. WinForm高级控件--PictureBox控件(图片控件)
  13. 北大美女辞去公司副总职务创业养狗
  14. 计算机进入睡眠和休眠,win7中睡眠和休眠的区别
  15. 创建服务器定时运行程序
  16. 数据库课程设计(民航售票子系统含数据库代码和前端代码)
  17. Matlab如何调整背景颜色
  18. 物联网智能开关平台源码
  19. 怎么将ppt文件压缩变小一点?
  20. fs.mkdir创建目录报错

热门文章

  1. 如何用程序删除win 7下SYSTEM权限的目录
  2. python能在生活中做什么-python能做哪些生活有趣的事情
  3. python恶搞表情包-用 Python 把你的朋友变成表情包
  4. 编程python用什么软件比较好-新手入门Python编程的8个实用建议
  5. python绘制笑脸-用python绘图
  6. 精通python设计模式-精通Python设计模式
  7. python 3d绘图-python - 轻松学会Matplotlib 3D绘图
  8. python基础题库-Python题库
  9. php和python交互-Python如何实现简单的用户交互程序(示例)
  10. python1000个常用代码-介绍Python中几个常用的类方法