我正在使用Asp.NET和MySql数据库。
申请流程:
我有一个代码的关键部分,可以在外部ERP资源上创建订单。对同一订单的多个请求可以同时运行,因为它们是从我无法控制的外部应用程序(woocommerce)创建的。因此,代码的关键部分必须只允许其中一个请求一次输入,否则可以创建重复的订单。
重要说明:应用程序托管在Elastic Beanstalk上,后者具有负载均衡器,因此应用程序可以跨多个服务器进行扩展,这使得标准C#锁定对象无法正常工作。
我想创建一个可以在多个服务器/应用程序实例之间共享的锁,这样只有一个服务器可以获取锁并一次输入代码的关键部分。我无法使用MySql和C#找到如何做到这一点,所以如果有人有一个很棒的例子。
下面是我如何进行单实例线程安全锁定。如何在多个实例中将其转换为安全:
SalesOrder newOrder = new SalesOrder(); //the external order object
var databaseOrder = new SalesOrderEntity(); //local MySql database object
/*
* Make this section thread safe so multiple threads can't try to create
* orders at the same time
*/
lock (orderLock)
{
//check if the order is already locked or created.
//wooOrder comes from external order creation application (WooCommerce)
databaseOrder = GetSalesOrderMySqlDatabase(wooOrder.id.ToString(), originStore);
if (databaseOrder.OrderNbr != null)
{
//the order is already created externally because it has an order number
return 1;
}
if (databaseOrder.Locked)
{
//the order is currently locked and being created
return 2;
}
//the order is not locked so lock it before we attempt to create externally
databaseOrder.Locked = true;
UpdateSalesOrderDatabase(databaseOrder);
//Create a sales order in external system with the specified values
newOrder = (SalesOrder) client.Put(orderToBeCreated);
//Update the order in our own database so we know it's created in external ERP system
UpdateExternalSalesOrderToDatabase(newOrder);
}
如果需要进一步的详细信息,请告诉我。
答案 0 :(得分:1)
您需要使用MySQL DBMS事务锁。
您不能直接显示您的DBMS查询,因此我无法猜测它们。你还需要这类查询。
START TRANSACTION;
SELECT col, col, col FROM wooTable WHERE id = <<<wooOrderId>>> FOR UPDATE;
/* do whatever you need to do */
COMMIT;
如果同一<<<wooOrderID>>>
行被另一个ELB服务器上运行的另一个Web服务器实例的同一序列查询命中,那个SELECT ... FOR UPDATE
查询将等待,直到第一个提交。
请注意,服务器内多线程和关键部分锁定既不必要也不足以解决您的问题。为什么呢?
这是不必要的,因为数据库连接首先不是线程安全的。
这是不够的,因为您需要一个数据库级事务,而不是进程级锁。
答案 1 :(得分:1)
您可以使用MySQL命名的咨询锁定功能GET_LOCK(name)
。
这在事务范围之外工作,因此您在释放锁之前更改了提交或回滚数据库。在此处阅读更多相关信息:https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-lock
您还可以使用其他一些专门的锁定服务。例如,您可以使用共享消息队列服务执行此操作。见https://softwareengineering.stackexchange.com/questions/127065/looking-for-a-distributed-locking-pattern
答案 2 :(得分:1)
您应该使用Transaction
,这是数据库中的一个工作单元。它使你的代码不仅是原子的,而且它也是线程安全的。以下是mysql official website
您需要的代码:
START TRANSACTION
COMMIT // if your transaction worked
ROLLBACK // in case of failure
另外,我强烈建议您阅读有关事务隔离级别的信息: Mysql Transaction Isolation Levels
如果你按照我上面的说法使用Transaction
,那么你就可以锁定你的桌面,这会阻止其他查询,例如选择查询,执行,他们将等待事务结束。它被称为“服务器阻塞”,以防止只是密集地读取链接。
答案 3 :(得分:0)
我认为使用数据库没有任何好的解决方案,除非一切都可以在存储过程中整齐地完成,如另一个建议的答案。对于其他任何事情,我会看一个带有多个编写器和一个读取器的消息队列解决方案。