Использовать сопоставление MySQL в Java - PullRequest
4 голосов
/ 07 октября 2009

Короткая версия

В настоящее время я смотрю на проблему с сопоставлениями MySQL и на то, как они влияют на набор значений (который отображается с помощью Hibernate, но это пока не должно иметь значения). Я хочу, чтобы набор строк использовал те же параметры сортировки, что и MySQL. Например. Я хочу, чтобы "foobar" и "fööbar" считались равными, но "foo bar" и "foobar" считались разными. Использование по умолчанию Collator.getInstance () Collator.PRIMARY сила) не работает надежно, так как есть различия ( в первую очередь пробелы). Итак, как получить Collator, который ведет себя так же, как MySQL для каждой возможной строки?

Длинная версия

Я хочу, чтобы в таблице был уникальный индекс, в котором я храню значения набора и проверяю, чтобы набор содержал только те значения, которые разрешены в БД и наоборот.

Таблица выглядит так:

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 в БД, 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

Но не работает для "foo bar" и "foobar", которые MySQL считает разными:

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!
}

Полный код для образца доступен: Скачать

1 Ответ

2 голосов
/ 07 октября 2009

Мне удалось заставить что-то работать самостоятельно. Поскольку я не мог заставить встроенные Collators делать то, что я хочу, я решил реализовать что-то сам. Я разместил свои выводы в своем блоге . Основная идея состояла в том, чтобы прочитать файлы определения набора символов / сопоставления MySQL (/ usr / share / mysql / charsets в моих системах Ubuntu). Альтернативным подходом было бы создание правил для RuleBasedCollator из этих определений, но я решил создать свой собственный сборщик, который имеет меньше возможностей (параметры сортировки MySQL нельзя настроить с учетом регистра или нет - они либо есть, либо являются нет) и должен работать довольно хорошо.

...