java基础的用法

Mybatis的日志

一般都会使用工厂类来生成log对象,mybatis使用的自己的LogFactory,使用静态代码块来初始化logger对象

static {
    tryImplementation(new Runnable() {
      public void run() {
        useSlf4jLogging(); //这个地方没有使用线程的方式,都是按顺序执行的。当某一个logger类被初始化成功后,后面的logger类就不会在初始化。
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useCommonsLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useLog4J2Logging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useLog4JLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useJdkLogging();
      }
    });
    tryImplementation(new Runnable() {
      public void run() {
        useNoLogging();
      }
    });
  }
mybatis对大部分主流的日志框架都包装了一层。已slf4j为例:
setImplementation(org.apache.ibatis.logging.slf4j.Slf4jImpl.class);
实例化封装好的slf4j类。
public Slf4jImpl(String clazz) {
    Logger logger = LoggerFactory.getLogger(clazz); 

    if (logger instanceof LocationAwareLogger) {
      try {
        // check for slf4j >= 1.6 method signature
        logger.getClass().getMethod("log", Marker.class, String.class, int.class, String.class, Object[].class, Throwable.class);
        log = new Slf4jLocationAwareLoggerImpl((LocationAwareLogger) logger); //采用的slf4j的LocationAwareLogger
        return;
      } catch (SecurityException e) {
        // fail-back to Slf4jLoggerImpl
      } catch (NoSuchMethodException e) {
        // fail-back to Slf4jLoggerImpl
      }
    }

    // Logger is not LocationAwareLogger or slf4j version < 1.6
    log = new Slf4jLoggerImpl(logger);//这里做了一个兼容操作,低版本的时候采用的装饰器的操作,实际操作的是slf4j的logger日志操作
  }
取得slf4j的logger对象,应为slf4j本身已经对主流框架做了选择的操作,所有mybatis优先选用这个框架。

有两种方案可以采用:

第一种是装饰器的模式,持有实际操作的对象,使用统一的接口来操作日志。

第二种是采用适配器模式,将某个类适配到目标类上面。继承目标接口,操作实际类的方法。

Mybatis的ErrorContext

ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
内部是从线程里面拿取的ErrorContext的实例,保证在一个线程内部都可以取到同一个 ErrorContext
private static final ThreadLocal<ErrorContext> LOCAL = new ThreadLocal<ErrorContext>(); 

public static ErrorContext instance() {
    ErrorContext context = LOCAL.get();
    if (context == null) { --从ThreadLocal里面获取ErrorContext,如果没有context实例,先建一个。
      context = new ErrorContext();
      LOCAL.set(context);
    }
    return context;
  }

public ErrorContext store() {
    stored = this;
    LOCAL.set(new ErrorContext());
    return LOCAL.get();
  }

Mybatis的session缓存

在BaseExecutor里面,在查询里面在session内,都保持同一个localCache来存储数据,内部使用的是HashMap来存储数据。

PerpetualCache:
private Map<Object, Object> cache = new HashMap<Object, Object>(); --存储结果集,根据key值来获取和存储数据
key的生成规则是CacheKey来决定的。
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
看下里面的equals和hashcode方法就知道哪些决定这个cachekey唯一性:
public boolean equals(Object object) {
    if (this == object)
      return true;
    if (!(object instanceof CacheKey))
      return false;

    final CacheKey cacheKey = (CacheKey) object;

    if (hashcode != cacheKey.hashcode)
      return false;
    if (checksum != cacheKey.checksum)
      return false;
    if (count != cacheKey.count)
      return false;

    for (int i = 0; i < updateList.size(); i++) {
      Object thisObject = updateList.get(i);
      Object thatObject = cacheKey.updateList.get(i);
      if (thisObject == null) {
        if (thatObject != null)
          return false;
      } else {
        if (!thisObject.equals(thatObject))
          return false;
      }
    }
    return true;
  }
比较的是updateList里面的值是否相等,在前面放置了多个值,确定每一个都是相等的时候,产生的cachekey才是一致的。
private void doUpdate(Object object) {
    int baseHashCode = object == null ? 1 : object.hashCode();

    count++;
    checksum += baseHashCode;
    baseHashCode *= count; --这个是用来检验个数的

    hashcode = multiplier * hashcode + baseHashCode; --这个是用来生成新的HashCode,使用数据的hashCode来生成新的hashCode,来作为判断依据。

    updateList.add(object);
  }
有个注意的点是外部的对象的如果非java基本数据类型的时候,hashCode的生成都需要被重写,保证在某些情况下是一致的。
public CacheKey createCacheKey(MappedStatement ms, Object parameterObject, RowBounds rowBounds, BoundSql boundSql) {
    if (closed) throw new ExecutorException("Executor was closed.");
    CacheKey cacheKey = new CacheKey();
    cacheKey.update(ms.getId()); --String对象
    cacheKey.update(rowBounds.getOffset()); --int型的位移
    cacheKey.update(rowBounds.getLimit()); --int型的限制
    cacheKey.update(boundSql.getSql()); --String型的sql
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
    TypeHandlerRegistry typeHandlerRegistry = ms.getConfiguration().getTypeHandlerRegistry();
    for (int i = 0; i < parameterMappings.size(); i++) { // mimic DefaultParameterHandler logic
      ParameterMapping parameterMapping = parameterMappings.get(i);
      if (parameterMapping.getMode() != ParameterMode.OUT) {
        Object value;
        String propertyName = parameterMapping.getProperty();
        if (boundSql.hasAdditionalParameter(propertyName)) {
          value = 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);
        }
        cacheKey.update(value);
      }
    }
    return cacheKey;
  }




转载于:https://my.oschina.net/zooy/blog/605912

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值