最短的toString作为ehcache键

时间:2011-06-29 08:10:29

标签: java ehcache

我使用ehcache和ehcache-spring-annotations。 我们第一次选择HashCodeCacheKeyGenerator。非常好。 但是1个月前我们发现了“密钥重复”。 所以我们用StringCacheKeyGenerator替换了HashCodeCacheKeyGenerator。 “密钥复制”问题不见了,但是巨大的toString(使用apache ToStringBuilder)密钥分配堆内存(约200M) 因为参数对象(值对象)有很大的字段。

我做了非常简单的tostring,如下面的

VerySimpleToStringStyle$Ta,,,,,1|2|3,1|2|3,a|b|c,true|false,64|65|66,1.0|2.0|3.0,1.0|2.0|3.0,,,,,,,1|2|3,[a, b, c],{b=2, c=3, a=1},a|1|false|{b=2, c=3, a=1}|[a, b, c],A,[b, c, a],,,

如您所见,如果值为null,则没有字段名称,也没有值。 我希望使用SHA256,MD5哈希关于原来的toString,但同事和我担心“密钥重复”。

任何想法最大的toString方法的巨大价值对象作为ehcache密钥?

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;

public class VerySimpleToStringStyle extends ToStringStyle {
private static final long serialVersionUID = -8388711512639784062L;

public VerySimpleToStringStyle() {
     super();
     this.setUseClassName(true);
     this.setUseIdentityHashCode(false);
     this.setUseFieldNames(false);
     this.setContentStart("");
     this.setContentEnd("");
     this.setNullText("");

     this.setFieldSeparatorAtStart(false);
     this.setFieldSeparator(",");
     this.setFieldSeparatorAtEnd(false);

     this.setArrayStart("");
     this.setArraySeparator("|");
     this.setArrayEnd("");

}

private static class T {
    private String a = "a";
    private String a1 = null;
    private String cc1;
    private String cc2;
    private String cc3;
    private int[] i = new int[] {1, 2, 3};
    private long[] l = new long[] {1, 2, 3};
    private char[] c = new char[] {'a', 'b', 'c'};
    private boolean[] bl = new boolean[] {true, false};
    private byte[] b = new byte[] {64, 65, 66};
    private float[] f = new float[] {1, 2, 3};
    private double[] d = new double[] {1, 2, 3};
    private String bb1;
    private String bb2;
    private String bb3;
    private String bb4;
    private String bb5;
    private String bb6;
    private short[] s = new short[] {1, 2, 3};
    private List<String> list = new ArrayList<String>();
    private Map<String, String> m = new HashMap<String, String>();
    private Object[] o = new Object[] {"a", 1, false, m, list};
    private enum E {A, B, C};
    private E e = E.A;
    private static String x = "x";
    private transient String y = "y";
    private Set<String> set = new HashSet<String>();
    private String aa1;
    private String aa2;
    private String aa3;

    public T() {
        this.list.add("a");
        this.list.add("b");
        this.list.add("c");

        this.m.put("a", "1");
        this.m.put("b", "2");
        this.m.put("c", "3");

        this.set.add("a");
        this.set.add("b");
        this.set.add("c");
    }
}

public static void main(String[] args) {
    System.out.println(ToStringBuilder.reflectionToString(new T(), new VerySimpleToStringStyle()));
}
}

2 个答案:

答案 0 :(得分:0)

像sha256和MD5这样的散列函数大多数都可以。 Duplicated键问题通常称为键冲突。绝对没有办法确保不会发生冲突,因为哈希函数会产生有限的可能性。散列函数的质量会降低碰撞的可能性,但并非不可能。

为了确保碰撞永远不会发生,减少生成的密钥的大小,您可以做的是最大化使用值生成的密钥中的entropy。简单来说,使用压缩函数作为关键。但是,在您的情况下,toString构建器似乎已经获取了有关构建密钥的对象的所有信息,这使得将缓存作为已经包含您需要的所有信息的密钥的目的失败了。相反,密钥应该是您尝试缓存的对象的某种唯一标识符。

首先,确定可以用作唯一标识符的内容,因为密钥比生成密钥更重要。

找出处理碰撞的方法。

答案 1 :(得分:0)

正如第一个答案所说,答案是使用真正的散列函数。默认密钥生成器只使用Java hashCode方法。

尝试MessageDigestCacheKeyGenerator:http://code.google.com/p/ehcache-spring-annotations/wiki/MessageDigestCacheKeyGenerator

它可以使用Java MessageDigest API支持的任何散列算法,默认配置生成密钥数据的SHA-1散列。