在 MyBatis 中,引入缓存的目的是为提高查询效率,降低数据库压力。既然 MyBatis
引入了缓存,那么缓存中的key和value的值分别是什么?
可能很容易能回答出value的内容,不就是SQL的查询结果吗。那key是什么呢?是字符串,还是其他什么对象?
如果是字符串的话,那么大家首先能想到的是用SQL语句作为key。但这是不对的,比如:
1
   | SELECT * FROM author where id > ?
   | 
 
id > 1 和 id > 10 查出来的结果可能是不同的,所以我们不能简单的使用SQL语句作为key
- 运行时参数将会影响查询结果,因此我们的key应该涵盖运行时参数。
 
- 除此之外,进行分页查询,查询结果也会不同,因此key也应该涵盖分页参数。
 
综上,我们不能使用简单的 SQL 语句作为 key。应该考虑使用一种复合对象,能涵盖
可影响查询结果的因子。在 MyBatis 中,这种复合对象就是 CacheKey。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
   | public class CacheKey implements Cloneable, Serializable {     private static final int DEFAULT_MULTIPLYER = 37;     private static final int DEFAULT_HASHCODE = 17;     // 乘子,默认为 37     private final int multiplier;     // CacheKey 的 hashCode,综合了各种影响因子     private int hashcode;     // 校验和     private long checksum;     // 影响因子个数     private int count;     // 影响因子集合     private List<Object> updateList;          public CacheKey() {         this.hashcode = DEFAULT_HASHCODE;         this.multiplier = DEFAULT_MULTIPLYER;         this.count = 0;         this.updateList = new ArrayList<Object>();     } }
  | 
 
除了 multiplier 是恒定不变的 ,其他变量将在更新操作中被修改
1 2 3 4 5 6 7 8 9 10 11 12 13 14
   | /** 每当执行更新操作时,表示有新的影响因子参与计算 */ public void update(Object object) {     int baseHashCode = object == null ? 1 : ArrayUtil.hashCode(object);     // 自增 count     count++;     // 计算校验和     checksum += baseHashCode;     // 更新 baseHashCode     baseHashCode *= count;     // 计算 hashCode     hashcode = multiplier * hashcode + baseHashCode;     // 保存影响因子     updateList.add(object); }
   | 
 
当不断有新的影响因子参与计算时,hashcode 和 checksum 将会变得愈发复杂和随机。
这样可降低冲突率,使 CacheKey 可在缓存中更均匀的分布。CacheKey 最终要作为键存入HashMap,因此它需要覆盖 equals 和 hashCode 方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
   | public boolean equals(Object object) {     // 检测是否为同一个对象     if (this == object) {         return true;     }     // 检测 object 是否为 CacheKey     if (!(object instanceof CacheKey)) {         return false;     }     final CacheKey cacheKey = (CacheKey) object;     // 检测 hashCode 是否相等     if (hashcode != cacheKey.hashcode) {         return false;     }     // 检测校验和是否相同     if (checksum != cacheKey.checksum) {         return false;     }     // 检测 coutn 是否相同     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 (!ArrayUtil.equals(thisObject, thatObject)) {             return false;         }     }          return true; }
  public int hashCode() {     // 返回 hashcode 变量     return hashcode; }
  | 
 
- equals 方法的检测逻辑比较严格,对CacheKey中多个成员变量进行了检测,已保证两者相等。
 
- hashCode 方法比较简单,返回 hashcode 变量即可。