c#从mysql数据库获取关键代码段的锁

lhcgjxsq  于 2021-06-21  发布在  Mysql
关注(0)|答案(4)|浏览(696)

我正在使用asp.net和mysql数据库。
申请流程:
订单在woocommerce中创建并发送到我的应用程序
我的应用程序将woo order对象转换为要添加到外部erp系统的对象
在外部erp系统中创建订单,我们用该订单信息更新本地数据库,以知道创建成功
我有一段关键的代码,可以在外部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);

}

如果需要进一步的细节,请告诉我。

8iwquhpp

8iwquhpp1#

您可以使用mysql的命名顾问锁函数 GET_LOCK(name) 为了这个。
这在事务范围之外工作,因此在释放锁之前,必须提交或回滚数据库更改。请在此处阅读更多信息:https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_get-锁定
你也可以使用其他专用的锁服务。例如,您可以使用共享消息队列服务来实现这一点。看到了吗https://softwareengineering.stackexchange.com/questions/127065/looking-for-a-distributed-locking-pattern

ao218c7q

ao218c7q2#

你应该使用 Transaction ,这是数据库中的工作单元。它使你的代码不仅是原子的,而且是线程安全的。以下是mysql官方网站的一个示例
您需要的代码:

START TRANSACTION

COMMIT // if your transaction worked
ROLLBACK // in case of failure

另外,我强烈建议您阅读事务隔离级别:mysql事务隔离级别
如果你使用 Transaction 如上所述,您的表上有一个锁,它阻止执行其他查询,例如select查询,它们将等待事务结束。它被称为“服务器阻塞”,为了防止这种情况,只需密集地读取链接。

fgw7neuy

fgw7neuy3#

我不认为使用数据库有什么好的解决方案,除非一切都可以像另一个答案所建议的那样在存储过程中整洁地完成。对于其他问题,我将研究具有多个编写器和单个读取器的消息队列解决方案。

x0fgdtte

x0fgdtte4#

为此,需要使用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 查询将等待第一个执行提交。
请注意,服务器内多线程和关键部分锁定对于解决您的问题既不必要也不充分。为什么?
这是不必要的,因为数据库连接首先不是线程安全的。
这是不够的,因为您需要数据库级事务,而不是进程级锁。

相关问题