我有一个POS系统,用于在两个不同的位置创建收据。我现在遇到的问题是,当两个位置同时输入收据时,他们会有相同的收据ID,因此,我做了一个非常糟糕的方法来解决这个问题。
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表(a,b,c)VALUES(1,2,3) ON DUPLICATE KEY UPDATE c = c + 1;
然而,这更新旧记录而不是新记录,是否有另一种方法可以更新我试图插入的记录如果发现重复?
谢谢
答案 0 :(得分:1)
经典并发控制问题。现代关系数据库通过让数据库生成ID来处理这个问题。在内部,数据库使用mutex来确保只有一个线程能够立即递增计数器。这通常通过序列或包含该功能的特殊数据类型在SQL中公开。在MySQL中,有一种称为SERIAL的特殊数据类型,它将使用MySQL的内部序列生成器AUTO_INCREMENT自动处理ID。
否则,您必须自己实现锁定和并发控制。我不建议这样做,因为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;
答案 1 :(得分:0)
visual studio有一个很棒的工具叫做.net的实体框架,有一个guide to use it with MySQL。它会让一切变得更安全,更容易,建议你使用它。
如果出现问题,使用实体框架和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;
}
}