代码之家  ›  专栏  ›  技术社区  ›  sfussenegger

在Java中使用MySQL排序规则

  •  4
  • sfussenegger  · 技术社区  · 15 年前

    短版

    我目前正在研究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

    1 回复  |  直到 15 年前
        1
  •  2
  •   sfussenegger    15 年前

    我自己也设法做了些事情。由于我无法让内置的collator做我想做的事情,我决定自己实现一些东西。 I've posted my findings on my blog . 基本思想是读取MySQL的字符集/排序规则定义文件(在我的Ubuntu系统上为/usr/share/MySQL/charsets)。另一种方法是根据这些定义为RuleBasedCollector构建规则,但我决定构建我自己的collator,它的功能较少(MySQL排序规则不能配置为区分大小写,也不能配置为区分大小写,它们要么是,要么不是),并且应该运行得很好。