短版
我目前正在研究MySQL排序规则的一个问题,以及它们如何影响一组值(使用Hibernate映射,但现在这不重要)。我希望有一组字符串使用与MySQL相同的排序规则。例如,我希望“foobar”和“fbar”被视为相等,但“foobar”和“foobar”被视为不同。使用默认值
Collator.getInstance()
(有
Collator.PRIMARY
强度)不能可靠地工作,因为仍然存在差异(最明显的是空白)。那么,对于每个可能的字符串,如何获得一个行为与MySQL相同的Collator呢?
长版本
CREATE TABLE `MY_SET` (
`entity_id` int NOT NULL,
`value` varchar(255) NOT NULL,
UNIQUE `entity-value`(`entity_id`, `value`)
) ENGINE = InnoDB DEFAULT CHARSET=latin1 DEFAULT COLLATION=;
现在,如果我使用普通字符串和哈希集来保存我的值,例如
public class MyValues {
private MyEntity _myEntity;
private final HashSet<String> _values = new HashSet<String>();
}
Collator
要检查字符串是否相等,请执行以下操作:
public class MyValues {
private MyEntity _entity;
private final HashSet<CollatedString> _values = new HashSet<CollatedString>();
}
public static class CollatedString {
private String _string;
private CollationKey _key;
public String getString() {
return _string;
}
public void setString(final String string) {
_string = string;
_key = getCollator().getCollationKey(_string);
}
@Override
public int hashCode() {
return _key.hashCode();
}
@Override
public boolean equals(final Object obj) {
if (!(obj instanceof CollatedString)) {
return false;
}
return _key.equals(((CollatedString) obj)._key);
}
}
这对“foobar”和“fbar”很有效:
final MyEntity e = new MyEntity();
final MyValues v = new MyValues();
v.setEntity(e);
v.getValues().add(new CollatedString("foobar"));
v.getValues().add(new CollatedString("fööbar"));
System.out.println("1 == " + v.getValues().size()); // prints 1 == 1
但不适用于MySQL认为不同的“foobar”和“foobar”:
v.getValues().add(new CollatedString("foobar"));
v.getValues().add(new CollatedString("foo bar"));
System.out.println("2 == " + v.getValues().size()); // prints 2 == 1 (which is wrong)
基本上,剩下要做的就是实现
getCollator()
public static final Collator getCollator() {
// FIXME please help!
}
示例的完整代码可用:
Download