"Дублировать запись для ключевого первичного" на одной машине, но не другую, с теми же данными?

Моя проблема: вставка набора данных работает в моей локальной машине/базе данных MySQL, но при производстве она вызывает ошибку Duplicate entry for key 'PRIMARY'. Насколько я могу судить, обе установки эквивалентны.

Моя первая мысль заключалась в том, что это проблема сортировки, но я проверил, что таблицы в обеих базах данных используют utf8_bin.

Стол пуст, и я делаю .Distinct() в коде, поэтому не должно быть дубликатов записей.

Таблица, о которой идет речь:

CREATE TABLE `mytable` (
  `name` varchar(100) CHARACTER SET utf8 NOT NULL,
  `appid` int(11) NOT NULL,
  -- A few other irrelevant fields
  PRIMARY KEY (`name`,`appid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;

Database.cs:

[DbConfigurationType(typeof(MySql.Data.Entity.MySqlEFConfiguration))]
public class Database : DbContext
{
    public DbSet<MyTable> MyTable { get; set; }
    public static Database Get()
    {
        /* Not important */
    }
    //etc.
}

MyTable.cs:

[Table("mytable")]
public class MyTable : IEquatable<MyTable>, IComparable, IComparable<MyTable>
{
    [Column("name", Order = 0), Key, Required, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public string Name
    {
        get { return _name; }
        set { _name = value.Trim().ToLower(); }
    }

    private string _name;

    [Column("appid", Order = 1), Key, Required, DatabaseGenerated(DatabaseGeneratedOption.None)]
    public int ApplicationId { get; set; }

    //Equals(), GetHashCode(), CompareTo(), ==() etc. all auto-generated by Resharper to use both Name and ApplicationId.
    //Have unit-tests to verify they work correctly.
}

Затем, используя его:

using(Database db = Database.Get())
using(DbContextTransaction transaction = db.Database.BeginTransaction(IsolationLevel.ReadUncommitted))
{
    IEnumerable<MyTable> newEntries = GetNewEntries();
    //Verify no existing entries already in the table; not necessary to show since table is empty anyways
    db.MyTable.AddRange(newEntries.Distinct());
}

Я не понимаю, как могут быть дублированные записи в базе данных после выполнения .Distinct() в коде при использовании utf8_bin, тем более, что он работает на одной машине, но не в другой. У кого-нибудь есть идеи?

Ответ 1

В итоге я решил его выполнить с помощью unicode-escape-символов, отличных от ascii, подобно этому решению.

Однако я до сих пор не знаю, почему это могло произойти...

Ответ 2

Я бы исследовал следующие моменты:

  • проверьте версию MySQL на обеих машинах. Вы можете сделать это в клиенте MySQL с помощью SHOW VARIABLES LIKE "%version%";
  • используйте SELECT HEX(name), чтобы узнать, как кодируются данные, для повторяющейся строки.
  • исследуйте, хранятся ли данные "utf8" в utf8mb3 или utf8mb4

https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb3.html

https://dev.mysql.com/doc/refman/5.7/en/charset-unicode-utf8mb4.html

Предполагая, что на машине dev данные вставляются из новой установки, а на производственной машине данные могут быть вставлены с более старой версией, а затем обновлен сервер, я бы проверял, в частности, если необходимы действия ( и были выполнены), чтобы правильно выполнить процесс обновления.

В частности, см. эти разделы (для правильной версии) в справочном руководстве MySQL:

https://dev.mysql.com/doc/refman/5.7/en/checking-table-incompatibilities.html

При необходимости перестройте индексы.

https://dev.mysql.com/doc/refman/5.7/en/rebuilding-tables.html

Изменить (2016-10-12)

Все вышеописанное основное внимание уделяется таблице и хранению.

Другая часть для проверки - это соединение между клиентом и сервером с такими переменными, как character_set_connection.

Пожалуйста, проверьте все системные переменные, связанные с набором символов, для их сравнения.

mysql> show variables like "%character%";
+--------------------------+-------------------------------------------+
| Variable_name            | Value                                     |
+--------------------------+-------------------------------------------+
| character_set_client     | utf8                                      |
| character_set_connection | utf8                                      |
| character_set_database   | latin1                                    |
| character_set_filesystem | binary                                    |
| character_set_results    | utf8                                      |
| character_set_server     | latin1                                    |
| character_set_system     | utf8                                      |
| character_sets_dir       | /home/malff/GIT_TRUNK/sql/share/charsets/ |
+--------------------------+-------------------------------------------+
8 rows in set (0.02 sec)

Ответ 3

Обе машины используют одни и те же драйверы базы данных? У меня были аналогичные проблемы с EF и Oracle, когда установлены разные драйверы.

EDIT:

Этот документ

https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html

говорит, что до MySQL 5.5.3 символы Юникода были сохранены с использованием макс. 3 байта на символ и после этого были сохранены с использованием 4 байтов. Это может объяснить разницу в том, является ли ключ уникальным. Разница вступает в игру, когда используются "дополнительные символы", поскольку старые версии не могут хранить эти символы вообще.

Являются ли ваши две базы данных по разные стороны разрыва (MySQL 5.5.3)?

Ответ 4

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

Проверьте это: http://dev.mysql.com/doc/refman/5.7/en/string-literals.html#character-escape-sequences