我使用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()));
}
}
答案 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散列。