如何在现有C# SQL下单逻辑中实现订单配送司机轮循分配
实现方案
核心逻辑
轮循分配的核心是用「当前累计有效订单数对司机总数取模」得到索引,匹配对应司机即可,规则适配你的需求:
- 先查询司机表获取所有正常可用的司机列表,按
driverid升序排序保证轮循顺序固定 - 统计当前已经生成的有效订单总数量(可自行过滤已取消等无效订单)
- 计算索引:
司机索引 = 总订单数 % 司机总数,刚好适配列表从0开始的下标规则,比如3个司机的场景:总订单数0取模得0对应driver1,总订单数2取模得2对应driver3,总订单数3取模得0回到driver1,完全符合轮循要求 - 取出对应索引的
driverid赋值给插入语句的司机字段即可
代码修改示例
在你原有的订单插入逻辑之前新增司机分配逻辑即可,同时建议将原有的SQL字符串拼接改为参数化查询,避免SQL注入风险:
string deliveryDate = DateTime.Now.AddDays(2).ToString("M/d/yyyy"); SqlConnection con = new SqlConnection(str); // ========== 新增:轮循分配司机逻辑开始 ========== con.Open(); // 1. 查询所有可用司机,按id排序保证轮循顺序固定,is_enabled为司机是否启用的标识,没有该字段可以去掉条件 SqlCommand driverCmd = new SqlCommand("SELECT driverid FROM Driver ORDER BY driverid ASC", con); SqlDataAdapter driverDa = new SqlDataAdapter(driverCmd); DataTable driverDt = new DataTable(); driverDa.Fill(driverDt); int driverCount = driverDt.Rows.Count; if(driverCount == 0){ // 无可用司机的异常处理 Response.Write("<script>alert('当前暂无可用配送司机,请稍后再试');</script>"); con.Close(); return; } // 2. 查询当前已有的有效订单总数 SqlCommand orderCountCmd = new SqlCommand("SELECT COUNT(*) FROM OrderDetails", con); int totalOrderCount = Convert.ToInt32(orderCountCmd.ExecuteScalar()); // 3. 计算本次分配的司机索引 int driverIndex = totalOrderCount % driverCount; string driverid = driverDt.Rows[driverIndex]["driverid"].ToString(); con.Close(); // ========== 新增:轮循分配司机逻辑结束 ========== if (Session["buyitems"] != null && Session["Orderid"] != null) { DataTable dt = (DataTable)Session["buyitems"]; for (int i = 0; i <= dt.Rows.Count - 1; i++) { string pId = dt.Rows[i]["pid"].ToString(); int pQuantity = Convert.ToInt16(dt.Rows[i]["pquantity"]); SqlDataAdapter sda = new SqlDataAdapter("Select Pquantity from ProductShirt where ProductId ='" + pId + "' ", con); DataTable dtbl = new DataTable(); sda.Fill(dtbl); int quantity = Convert.ToInt32(dtbl.Rows[0][0]); if (quantity > 0) { con.Open(); // 改为参数化查询避免SQL注入 string insertSql = @"insert into OrderDetails(orderid,sno,productid,productname,price,quantity,orderdate,status,email,deliverydate,address, driverid) values(@orderid,@sno,@productid,@productname,@price,@quantity,@orderdate,'Pending',@email,@deliverydate,@address, @driverid)"; SqlCommand cmd = new SqlCommand(insertSql, con); cmd.Parameters.AddWithValue("@orderid", Session["Orderid"].ToString()); cmd.Parameters.AddWithValue("@sno", dt.Rows[i]["sno"]); cmd.Parameters.AddWithValue("@productid", dt.Rows[i]["pid"]); cmd.Parameters.AddWithValue("@productname", dt.Rows[i]["pname"].ToString()); cmd.Parameters.AddWithValue("@price", Convert.ToInt32(dt.Rows[i]["pprice"])); cmd.Parameters.AddWithValue("@quantity", dt.Rows[i]["pquantity"]); cmd.Parameters.AddWithValue("@orderdate", DateTime.Now.ToString("M/d/yyyy")); cmd.Parameters.AddWithValue("@email", Session["username"].ToString()); cmd.Parameters.AddWithValue("@deliverydate", deliveryDate); cmd.Parameters.AddWithValue("@address", TextBox1.Text); cmd.Parameters.AddWithValue("@driverid", driverid); cmd.ExecuteNonQuery(); con.Close(); } } decreaseQuantity(); clearCart(); Session["buyitems"] = null; Session["deliverydate"] = deliveryDate; Response.Redirect(url); } else { Response.Redirect("AddtoCart.aspx"); }
高并发场景优化
如果站点订单并发量较高,可能出现多个请求同时查询到相同总订单数、分配到同一个司机的问题,可做如下优化:
- 单独创建计数器表
DispatchCounter,仅存储current_count整数字段记录轮询计数 - 每次分配司机时先执行原子更新操作
UPDATE DispatchCounter SET current_count = current_count + 1,再读取更新后的计数值计算司机索引,避免并发重复分配
内容的提问来源于stack exchange,提问作者MikeWizowski
相关产品推荐
相关产品推荐

