WordPress中如何处理同时更新同一用户元数据的AJAX请求?
问题原因
并发点击时,每个AJAX请求都会先读取当前用户的saved数组,各自添加新文章ID后再写入数据库。由于请求几乎同时进行,所有请求读取到的都是同一个初始数组,后完成的请求会覆盖前面请求的写入结果,最终只有最后一个ID被保留。
解决方案
方案一:单条元数据存储单篇文章(推荐)
放弃用数组存储所有ID,改为给每个已保存的文章创建独立的用户元数据条目,从根本上避免并发冲突。
修改后的PHP函数
function add_postID_to_user_saved_list($post_id) { $user_id = get_current_user_id(); // 键名唯一,重复添加会自动忽略,天然去重 add_user_meta($user_id, "saved_post_{$post_id}", 1, true); }
查询已保存文章ID的方法
如果需要获取用户所有已保存的文章ID,可通过遍历用户元数据提取:
$user_id = get_current_user_id(); $saved_post_ids = []; // 获取用户所有元数据(第二个参数为空字符串) $all_meta = get_user_meta($user_id, '', true); foreach ($all_meta as $meta_key => $meta_value) { if (str_starts_with($meta_key, 'saved_post_')) { $saved_post_ids[] = (int) str_replace('saved_post_', '', $meta_key); } }
优势
- 彻底解决并发覆盖问题,每个请求操作独立的元数据条目,互不干扰
- 删除单篇已保存文章更方便,直接调用
delete_user_meta($user_id, "saved_post_{$post_id}")即可
方案二:原子更新数组(保留原存储结构)
如果必须保持数组存储的方式,可通过数据库层面的原子操作,避免先读再写的竞态条件。
修改后的PHP函数
function add_postID_to_user_saved_list($post_id) { global $wpdb; $user_id = get_current_user_id(); $meta_key = 'saved'; // 直接在数据库中修改序列化数组,实现原子添加 $wpdb->query( $wpdb->prepare( "UPDATE $wpdb->usermeta SET meta_value = CASE WHEN meta_value = '' OR meta_value = 'a:0:{}' THEN %s ELSE CONCAT(LEFT(meta_value, LENGTH(meta_value)-1), ', %d}') END WHERE user_id = %d AND meta_key = %s", serialize([$post_id]), $post_id, $user_id, $meta_key ) ); // 如果元数据不存在,添加新数组 if ($wpdb->rows_affected === 0) { add_user_meta($user_id, $meta_key, [$post_id], true); } }
说明
- 利用SQL语句直接修改数据库中的序列化数组,跳过了先读取再写入的步骤,避免并发冲突
- 兼容WordPress对数组元数据的序列化存储格式,确保数据结构正确
内容的提问来源于stack exchange,提问作者Power
相关产品推荐
相关产品推荐

