如何解决维护 MySQL WooCommerce 客户表的问题
好吧,恐怕我无法发布最低限度的可重现示例,为此我深表歉意。但是,这里什么也没有。
我们是每周准备餐点服务。我以多种方式跟踪订单量。这是相关表的结构:
然后,我以多种方式利用突出显示的字段,例如,如果客户从一个多月前的先前订单返回(last_order_w - prev_order_w > 4),例如,向送货司机指示。
最近我注意到数据没有持续正确更新。在过去的 3 周内,我会说它的发生率为 5%。如果它更一致,我会对我追踪问题的能力更有信心,但我什至不知道如何激发它,因为我只是在事后才真正注意到它。
应该导致更新的代码如下:
<?PHP
//retrieve and iterate over IDs of orders placed since last synchronization.
$newOrders=array_map('reset',$dbh->query("select id from wp_posts where id > (select max(synced) from fitaf_weeks) and post_type='shop_order' and post_status='wc-processing'")->fetchAll(PDO::FETCH_NUM));
foreach($newOrders as $no){
//retrieve the Metadata for the current order
$newMetas=array_map('reset',$dbh->query("select Meta_key,Meta_value from wp_postMeta where post_id=$no")->fetchAll(PDO::FETCH_GROUP|PDO::FETCH_UNIQUE));
//check if the current order is associated with an existing customer
$exist=$dbh->query("select * from fitaf_customers where id=".$newMetas['_customer_user'])->fetch();
//if not,gather the information we want to store from this post
$noExist=[$newMetas['_customer_user'],$newMetas['_shipping_first_name'],$newMetas['_shipping_last_name'],$newMetas['_shipping_address_1'],(strlen($newMetas['_shipping_address_2'])==0?NULL:$newMetas['_shipping_address_2']),$newMetas['_shipping_city'],$newMetas['_shipping_state'],$newMetas['_shipping_postcode'],$phone,$newMetas['_billing_email'],1,$no,$newMetas['_paid_date'],$week[3],$newMetas['_order_total']];
if($exist){
//if we found a record in the customer table,retrieve the data we want to modify
$oldO=$dbh->query("select last_order_id,last_order,last_order_w,lo,num_orders from fitaf_customers where id=".$newMetas['_customer_user'])->fetch(PDO::FETCH_GROUP|PDO::FETCH_ASSOC|PDO::FETCH_UNIQUE);
//make changes to the retrieved data,and make sure we are storing the most recently used delivery address and prepare the data points for the update command
$exists=[$phone,$oldO['last_order'],$oldO['last_order_id'],$oldO['last_order_w'],($oldO['num_orders']+1),($oldO['lo']+$newMetas['_order_total']),$newMetas['_customer_user']];
}
if(!$exist){
//if the customer did not exist,perform an insert
$dbh->prepare("insert into fitaf_customers(id,fname,lname,addr1,addr2,city,state,zip,phone,email,num_orders,num_weeks,last_order_id,lo) values(?,?,?)")->execute($noExist);
}
else{
//if the customer did exist,update their data
$dbh->prepare("update fitaf_customers set phone=?,fname=?,lname=?,zip=?,addr1=?,addr2=?,city=?,`state`=?,last_order=?,last_order_id=?,last_order_w=?,prev_order=?,prev_order_id=?,prev_order_w=?,num_orders=?,lo=? where id=?")->execute($exists);
}
}
//finally retrieve the most recent post ID and update the field we check against when the syncornization script runs
$lastPlaced=$dbh->query('select max(id) from wp_posts where post_type="shop_order"')->fetch()[0];
$updateSync=$dbh-> query("update fitaf_weeks set synced=$lastPlaced order by id desc limit 1");
?>
不幸的是,我没有任何相关的错误日志可以显示,但是,当我记录了这篇文章的代码时,我意识到了一个潜在的缺点。我应该利用从新帖子的初始查询中检索到的数据,而不是在执行此逻辑后选择最高的帖子 ID。但是,我的脚本上运行了计时器,并且此部分很长时间没有运行超过 3 秒。因此,每 5 分钟在 cron 上运行一次的脚本似乎不太可能遇到这种意外重叠?
虽然我已经做出更改以从 $newOrders 中弹出最高 ID,并希望它解决问题,但我仍然很想知道是否有人对在如此低的发生率下可能导致此逻辑失败的原因有任何见解.
解决方法
您的问题似乎来自访问您的数据库的多个操作之间的竞争条件。
首先,您的最后几行代码执行 SELECT MAX(ID)
,然后使用该值更新某些内容。你不能那样做™。如果其他人在您认为相关的条目之后随时向该 wp_posts
表添加一行,您将使用错误的 ID。我不太了解您的应用程序,无法推荐修复程序。但我知道这是一个严重且臭名昭著的问题。
您还有另一种可能的竞争条件。你的逻辑是这样的:
-
选择一些东西。
-
根据您选择的内容做出决定。
-
根据该决定插入或更新。
如果由数据库的其他用户执行的其他操作会在第 1 步和第 3 步之间进行干预,那么您的决定可能是错误的。
您可以通过数据库事务解决此问题。 ->beginTransaction()
operation 开始交易。 ->commit()
operation concludes 它。还有,您在第一步 should say SELECT ... FOR UPDATE
中使用的 SELECT 操作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。