4

简洁版本

我目前正在研究 MySQL 排序规则的问题以及它们如何影响一组值(使用 Hibernate 映射,但现在应该不重要)。我想拥有一组使用与 MySQL 使用相同的排序规则的字符串。例如,我希望“foobar”和“fööbar”被认为是相等的,但“foo bar”和“foobar”被认为是不同的。使用默认Collat​​or.getInstance()(具有Collat​​or.PRIMARY强度)不能可靠地工作,因为仍然存在差异(最明显的是空格)。那么如何为每个可能的 String 获得一个与 MySQL 表现相同的 Collat​​or?

长版

我想在存储 Set 值的表上有一个唯一索引,并确保 Set 仅包含数据库中允许的值,反之亦然。

表如下所示:

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=;

现在,如果我使用普通字符串和 HashSet 来保存我的值,例如

public class MyValues {
  private MyEntity _myEntity;
  private final HashSet<String> _values = new HashSet<String>();
}

可以将“foobar”和“fööbar”都添加到值集中。现在,如果 Hibernate 将 Set 刷新到 DB,MySQL 将抱怨“foobar”和“fööbar”对定义的“实体值”键重复。因此,我想我包装字符串并使用Collat​​or来检查字符串是否相等:

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" 和 "fööbar":

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 认为不同的“foo bar”和“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)

基本上剩下要做的就是实现getCollat​​or()方法:

public static final Collator getCollator() {
  // FIXME please help!
}

示例的完整代码可用:下载

4

1 回答 1

2

我已经设法让自己工作。由于我无法让内置的 Collat​​ors 做我想做的事,我决定自己实现一些东西。我已经在我的博客上发布了我的发现。基本思想是读取 MySQL 的字符集/排序规则定义文件(我的 Ubuntu 系统上的 /usr/share/mysql/charsets)。另一种方法是根据这些定义为 RuleBasedCollat​​or 构建规则,但我决定构建自己的整理器,它的功能较少(MySQL 排序规则不能配置为区分大小写 - 它们要么是要么是不是)并且应该表现得很好。

于 2009-10-07T17:25:54.460 回答