在 Java 中使用 MySQL 排序规则

Posted

技术标签:

【中文标题】在 Java 中使用 MySQL 排序规则【英文标题】:Use MySQL collation in Java 【发布时间】: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,但当你的专业知识远高于一般的 *** 公众时,这就是你付出的代价。 好问题,希望我能给它+10! 【参考方案1】:

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

【讨论】:

以上是关于在 Java 中使用 MySQL 排序规则的主要内容,如果未能解决你的问题,请参考以下文章

在 MySQL 中,我应该选择哪种排序规则?

MySQL如何指定字符集和排序规则?

发现 MySQL 列的排序规则

SQL Server 与MySQL中排序规则与字符集相关知识的一点总结

MySQL 根据自定义规则排序

MySQL排序顺序 - 排序规则?