【问题标题】:Use MySQL collation in Java在 Java 中使用 MySQL 排序规则
【发布时间】:2010-12-04 14:30:54
【问题描述】:

短版

我目前正在研究 MySQL 排序规则的问题以及它们如何影响一组值(使用 Hibernate 进行映射,但现在应该不重要)。我想拥有一组使用与 MySQL 使用相同的排序规则的字符串。例如。我希望“foobar”和“fööbar”被认为是相同的,但“foo bar”和“foobar”被认为是不同的。使用默认的 Collator.getInstance()(具有 Collator.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”对定义的“实体值”键重复。因此,我想我包装字符串并使用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”和“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!
}

示例的完整代码可用:Download

【问题讨论】:

  • 啊,成为真正的专家的悲哀。我只是花了两个小时在谷歌上搜索有关 MySQL 的 unicode_general_ci 排序规则和 Java 的 Collator 类的惯常做法,但我找不到专门问这个问题的人:这两者有什么关系?很遗憾看到你得到 0 个答案和 cmets,但当你的专业知识远高于一般的 StackOverflow 公众时,这就是你付出的代价。 好问题,希望我能给它+10!

标签: java mysql hibernate collation


【解决方案1】:

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

【讨论】:

    猜你喜欢
    • 2011-11-14
    • 2011-08-18
    • 2012-01-19
    • 1970-01-01
    • 2018-12-19
    • 1970-01-01
    • 2011-10-22
    • 2010-11-27
    • 1970-01-01
    相关资源
    最近更新 更多