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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是Java方法基础实验的介绍和演示: Java方法是一段可重用的代码块,可以接受输入并返回输出。在Java中,方法是类的一部分,可以在类中定义和调用。Java方法的语法如下: ```java 修饰符 返回类型 方法名(参数列表) { // 方法体 return 返回值; } ``` 其中,修饰符可以是public、private、protected或默认,返回类型可以是任何Java数据类型,方法名是标识符,参数列表是一组用逗号分隔的输入参数,方法体是一组执行语句,return语句用于返回方法的输出。 下面是一个Java方法的例子: ```java public class Calculator { public static int add(int a, int b) { return a + b; } } ``` 这个例子定义了一个名为add的静态方法,接受两个整数作为输入,返回它们的和。在另一个类中,可以通过以下方式调用这个方法: ```java int sum = Calculator.add(2, 3); ``` 这个调用将返回5,并将其赋值给变量sum。 现在,我们来进行一个Java方法基础实验。假设我们要编写一个程序,计算两个数的平均值。请按照以下步骤进行操作: 1.创建一个名为Average的类。 2.在Average类中定义一个名为calculateAverage的静态方法,接受两个double类型的参数,返回它们的平均值。 3.在calculateAverage方法中,使用以下代码计算平均值: ```java double average = (num1 + num2) / 2; ``` 其中,num1和num2是方法的输入参数。 4.在另一个类中,调用calculateAverage方法,并将其输出到控制台。 下面是完整的Java代码: ```java public class Average { public static double calculateAverage(double num1, double num2) { double average = (num1 + num2) / 2; return average; } } public class Main { public static void main(String[] args) { double num1 = 3.5; double num2 = 4.2; double average = Average.calculateAverage(num1, num2); System.out.println("The average of " + num1 + " and " + num2 + " is " + average); } } ``` 输出结果为: ``` The average of 3.5 and 4.2 is 3.85 ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值