2015-06-08 3 views
0

У меня есть система POS, которая будет использоваться для создания квитанций в двух разных местах. проблема, с которой я столкнулся сейчас, заключается в том, что, когда оба места вводят квитанцию ​​одновременно, у них будет одинаковый идентификатор квитанции, и поэтому я сделал довольно плохой способ устранить эту проблему.Повторяющийся ключ на mysql

while (!success) 
{ 
    try 
    { 
     MySqlCommand myCommand4 = new MySqlCommand("Insert into OrderRecords_table values('" + OrderID + "','" + customerCode + "','" + customer + "','" + TelComboBox.Text + "','" + LicenseComboBox.Text + "','" + 
       DriverComboBox.Text + "','" + AddressComboBox.Text + "','" + LocationTypeComboBox.Text + "','" + PickupComboBox.Text + "','" + CustomerTypeLabel.Text + "','" + 
      Convert.ToDecimal(TotalPriceLabel.Text) + "','" + status + "','" + note + "','" + sandReceiptNo + "','" + createtiming + "','" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "')", myConnection52); 
     myCommand4.ExecuteNonQuery(); 
     if (retried == true) 
     { 
      MessageBox.Show("收據號碼已改為: " + OrderID); 
     } 
     success = true; 
    } 
    catch (MySqlException ex) 
    { 
     switch (ex.Number) 
     { 
      case 1062: 
       retried = true; 
       OrderID = OrderID.Substring(0, 1) + (Convert.ToInt32(OrderID.Substring(1, OrderID.Length - 1)) + 1).ToString("00000"); 
       success = false; 
       break; 
     } 
    } 
} 

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

Я не знаю, как это нарушает правила на mysql. ситуация прямо сейчас выглядит следующим образом: если у меня есть запись с номером чека: m00001 (orderID col) , а другая программа пытается вставить номер квитанции, который также является m00001, он должен поймать это исключение, но это вставьте оба m00001 как-то. (столбец OrderID задан как первичный ключ).

я делал некоторые исследования в Интернете, чтобы увидеть, если есть другой способ, чтобы решить эту проблему, и я нашел этот

INSERT INTO таблицы (а, б, в) VALUES (1,2,3) ON DUPLICATE KEY UPDATE c = c + 1;

Однако это обновление старой записи вместо новой, есть ли другой способ, который будет обновлять тот, который я пытаюсь вставить, если он найден дублированным?

Thanks

+7

Вы действительно должны обрабатывать первичный ключ самостоятельно? Почему бы не создать базу данных с соответствующим ключом (с колонкой автоинкремента)? Кстати, вы должны изучить, как использовать параметризованные запросы - то, что вы делаете, подвержено атакам с инъекциями. – germi

+0

спасибо за ответ @germi, это возможно дать мне немного больше подробностей, я довольно новичок в этом. Кроме того, первичный ключ - это номер квитанции, в котором я избегаю иметь тот же номер квитанции в базе данных, поэтому я сделал его столбцом первичного ключа. –

+0

Большинство систем баз данных могут автоматически генерировать действительный первичный ключ самостоятельно, чтобы разработчику не нужно координировать несколько вставок. Изучите руководство по MySQL (https://dev.mysql.com/doc/refman/5.0/en/example-auto-increment.html). О параметризованных запросах, посмотрите [в этом учебнике] (http://zetcode.com/db/mysqlcsharptutorial/) (сначала я нашел через google, конечно же есть другие). – germi

ответ

1

Классический контроль параллелизма. Современные реляционные базы данных справляются с этой проблемой, создавая базу данных с идентификатором. Внутри базы данных используется mutex, чтобы гарантировать, что только один поток может постоянно увеличивать счетчик. Обычно это отображается в SQL через последовательности или специальный тип данных, который завершает работу. В MySQL существует специальный тип данных, называемый SERIAL, который будет обрабатывать идентификаторы автоматически с помощью генератора внутренней последовательности MySQL, который называется AUTO_INCREMENT.

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

Изменение существующего столбца для начала использования AUTO_INCREMENT - это тривиальная операция, которая может быть быстро выполнена против меньших наборов данных (менее миллиона строк или около того). Скажем, у вас есть таблица, которая выглядит следующим образом:

mysql> SHOW CREATE TABLE t_receipts; 
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| Table  | Create Table                                           | 
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
| t_receipts | CREATE TABLE `t_receipts` (
    `id` bigint(20) unsigned NOT NULL, 
    `amount` double(8,2) DEFAULT NULL, 
    `date_created` datetime DEFAULT NULL 
) ENGINE=InnoDB DEFAULT CHARSET=latin1 | 
+------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ 
1 row in set (0.01 sec) 

Преобразование таблицы так же просто, как:

ALTER TABLE t_receipts CHANGE id id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT; 

или, используя SERIAL ярлык:

ALTER TABLE t_receipts CHANGE id id SERIAL; 
+0

спасибо за ответ @diz, но я хотел бы иметь свой собственный уникальный идентификатор квитанции, например M00001 - M99999 и C00001 - C99999, работает ли автоматическое увеличение? –

+0

AUTO_INCREMENT работает только для числовых значений. Если вы хотите, чтобы ваш идентификатор квитанции содержал нечисловые символы, я бы порекомендовал одну из двух вещей: (1) внедрение пользовательского сопоставления идентификатора квитанции к идентификатору базы данных или (2) добавление дополнительного столбца UNIQUE, в который вы вставляете ваши специальные идентификаторы квитанций, генерируемые отдельной службой генерации идентификатора, которая реализует блокировку за пределами базы данных. Автоматически увеличивающиеся числовые первичные ключи необходимы для правильного проектирования базы данных в большинстве случаев (за исключением некоторых случаев с краями, конечно), поэтому вы должны использовать их независимо от того, что вы решаете. – diz

+0

Чтобы расширить отображение - я ранее реализовал такое отображение при разработке OLTP-системы. Идентификаторы заказов, предоставленные клиентам, содержали идентификаторы первичных ключей соответствующих записей базы данных, но были закодированы методом класса ORM, реализующего эту таблицу. Идентификаторы кодировки таким образом имеют то преимущество, что скрывают информацию о вашем объеме бизнеса. – diz

0

Visual Studio имеет отличный инструмент под названием entity framework для .net, есть guide to use it with MySQL. Это сделает все намного безопаснее и проще, это предложит вам использовать это.

Использование сущности Framework и Linq, если есть проблема, подобно дубликатному ключу, всегда будет генерировать исключение. Создание ключей, если вы не можете использовать автоматическое увеличение или GUID, немного легче из-за исключений, вы всегда будете знать, когда ключ, который вы пытались вставить, неверен.

Таблица в вашей базе данных будет просто классом в C# с моделью сущности, вы просто создаете новый объект этого класса, заполняете это поле, добавляете его в коллекцию (что соответствует записям в вашей базе данных) и сохранить. при сохранении он будет проверять, является ли он оригинальным, и запись будет создана.

Насколько я знаю, это никогда не позволит дублировать ключ независимо от того, сколько соединений и как одновременно добавляются записи.

пример кода для добавления с помощью LINQ к модели объекта:

MyDbEntities mydb = new MyDbEntities(); 
Order order = new Order(); 
order.OrderID = "m0000001"; 
try 
{ 
    mydb.Order.Add(order); 
    mydb.SaveChange(); 
} 
catch (Exception exception) 
{ 
    if(excpetion == duplicate key) // pseudo code, don't know the error for duplicate keys 
    { 
     order.OrderID = m0000002; 
    } 
} 
+0

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

+0

Что я могу понять, у меня были некоторые проблемы с инфраструктурой сущностей и linq в самом начале, но теперь я знаю, как им пользоваться. Я очень доволен. но имейте это в виду в следующий раз, тогда;) это действительно того стоит. – Vincent

+0

спасибо за это, но знаете ли вы, почему он не поймал дублирующее исключение в моем случае? –

Смежные вопросы