mybatis-executor包阅读

executor包主要功能

  • 前文说了DefaultSqlSession中有个成员变量Executor,Executor属于executor包用来执行数据库操作。
  • 更准确的说,Executor也并没有直接连接JDBC而是委托给了StatementHandler,根据不同类型的Statement去完成JDBC操作。
  • SimpleExecutor为默认的执行器(如下代码),每执行一次update或select,就开启一个Statement对象,用完立刻关闭,ReuseExecutor执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map<String, Statement>内,供下一次使用Statement对象,BatchExecutor可以批量执行update,将所有sql都添加到批处理中,等待统一executeBatch()(doFlushStatements方法就是先完成executeBatch()而后statementList.clear()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,逐一执行executeBatch(),由于JDBC批处理不支持select(int[] executeBatch(),批处理返回的是int数组,而select需要返回数据库字段),所以批处理只针对更新数据。
  configuration.setDefaultExecutorType(ExecutorType.valueOf(props.getProperty("defaultExecutorType", "SIMPLE")));

  • StatementHandler,PreparedStatementHandler,CallableStatementHandler,分别对应JDBC中的三种Statement。

executor包主要结构

executor包

executor包设计模式

  • CachingExcutor采用了装饰设计模式,每次执行sql的时候一定是首先过CachingExcutor的手,之后再委托给其它Executor执行,如果配置文件没有配置一级缓存为STATEMENT,那么就不清理一级缓存,一级缓存默认是SESSION级别,如下面代码块:
      if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
        // issue #482
        clearLocalCache();
      }
  • RoutingStatementHandler的设计也是用到了装饰设计模式,JDBC中有Statement,PreparedStatement,CallableStatement,RoutingStatementHandler的作用就是根据不同的Statment路由到这三种类型去调用JDBC,若在Mapper.xml内没有配置statementType属性,默认就是PreparedStatement,前文在builder包中分析过,XMLStatementBuilder类中:
    StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));

  • BaseExecutor、BaseStatementHandler都是抽象类,都用了模版方法设计模式,不同的实现类,分别实现自己的抽象方法完成不同的功能,附上源码做参考:
  protected abstract int doUpdate(MappedStatement ms, Object parameter)
      throws SQLException;

  protected abstract List<BatchResult> doFlushStatements(boolean isRollback)
      throws SQLException;

  protected abstract <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql)
      throws SQLException;

  protected abstract <E> Cursor<E> doQueryCursor(MappedStatement ms, Object parameter, RowBounds rowBounds, BoundSql boundSql)
      throws SQLException;
 
 ......
 
  protected abstract Statement instantiateStatement(Connection connection) throws SQLException;

  • 附上源码包结构做参考:
    executor包

优雅的异常打印

/**
 * @author Clinton Begin
 */
public class ErrorContext {

  private static final String LINE_SEPARATOR = System.getProperty("line.separator","\n");
  //多线程环境中,每个线程内部可以共用一份 ErrorContext,互不影响,保证异常日志正确输出
  private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<>();

  //充当中介,在调用 store() 方法时将当前 ErrorContext 保存下来,在调用 recall() 方法时将该 ErrorContext 实例传递给 LOCAL
  private ErrorContext stored;
  //异常是由谁在做什么的时候在哪个资源文件中发生的,执行的 SQL 是哪个,以及 Java 详细的异常信息
  private String resource;        //存储异常存在于哪个资源文件中
  private String activity;        //存储异常是做什么操作时发生的
  private String object;          //存储哪个对象操作时发生异常
  private String message;         //存储异常的概览信息
  private String sql;             //存储发生日常的 SQL 语句
  private Throwable cause;        //存储详细的 Java 异常日志

  private ErrorContext() {
  }

  public static ErrorContext instance() {
    ErrorContext context = LOCAL.get();
    if (context == null) {
      context = new ErrorContext();
      LOCAL.set(context);
    }
    return context;
  }

  //stored 变量充当一个中介,在调用 store() 方法时将当前 ErrorContext 保存下来,在调用 recall() 方法时将该 ErrorContext 实例传递给 LOCAL。
  public ErrorContext store() {
    ErrorContext newContext = new ErrorContext();
    newContext.stored = this;
    LOCAL.set(newContext);
    return LOCAL.get();
  }

  public ErrorContext recall() {
    if (stored != null) {
      LOCAL.set(stored);
      stored = null;
    }
    return LOCAL.get();
  }

  public ErrorContext resource(String resource) {
    this.resource = resource;
    return this;
  }

  public ErrorContext activity(String activity) {
    this.activity = activity;
    return this;
  }

  public ErrorContext object(String object) {
    this.object = object;
    return this;
  }

  public ErrorContext message(String message) {
    this.message = message;
    return this;
  }

  public ErrorContext sql(String sql) {
    this.sql = sql;
    return this;
  }

  public ErrorContext cause(Throwable cause) {
    this.cause = cause;
    return this;
  }

  public ErrorContext reset() {
    resource = null;
    activity = null;
    object = null;
    message = null;
    sql = null;
    cause = null;
    LOCAL.remove();
    return this;
  }

  @Override
  public String toString() {
    StringBuilder description = new StringBuilder();

    // message
    if (this.message != null) {
      description.append(LINE_SEPARATOR);
      description.append("### ");
      description.append(this.message);
    }

    // resource
    if (resource != null) {
      description.append(LINE_SEPARATOR);
      description.append("### The error may exist in ");
      description.append(resource);
    }

    // object
    if (object != null) {
      description.append(LINE_SEPARATOR);
      description.append("### The error may involve ");
      description.append(object);
    }

    // activity
    if (activity != null) {
      description.append(LINE_SEPARATOR);
      description.append("### The error occurred while ");
      description.append(activity);
    }

    // sql
    if (sql != null) {
      description.append(LINE_SEPARATOR);
      description.append("### SQL: ");
      description.append(sql.replace('\n', ' ').replace('\r', ' ').replace('\t', ' ').trim());
    }

    // cause
    if (cause != null) {
      description.append(LINE_SEPARATOR);
      description.append("### Cause: ");
      description.append(cause.toString());
    }

    return description.toString();
  }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值