亚洲有码Av一区二区三区_国产高清啪啪免费视频_69色视频国产_国产成人人人爆出白浆_国产精品自在线拍国_一本久久伊人热热精品无码_午夜性刺激在线看免费带字幕_助力高品质欧美狂喷水_亚洲精品日韩无码_精品无码一区二区三区蜜臀_麻豆高清国产AV_熟妇人素无码中文字幕_亚洲a级片在线观看_国产欧美日韩三区_99国产成人高清在线观看

ARTICLE DETAIL

資訊詳情

深耕商務(wù)建站與企業(yè)官網(wǎng)運(yùn)營(yíng)的一線(xiàn)實(shí)戰(zhàn)洞察。

C#火車(chē)訂票系統(tǒng)實(shí)戰(zhàn):并發(fā)控制與事務(wù)一致性設(shè)計(jì)

C#火車(chē)訂票系統(tǒng)實(shí)戰(zhàn):并發(fā)控制與事務(wù)一致性設(shè)計(jì) 簡(jiǎn)介一份基于C#與SQL Server的火車(chē)訂票系統(tǒng)完整項(xiàng)目面向初學(xué)C#窗體編程及數(shù)據(jù)庫(kù)開(kāi)發(fā)的讀者用于理解訂票、退票、改簽、車(chē)次管理等核心業(yè)務(wù)流程并掌握WinForms事件驅(qū)動(dòng)設(shè)計(jì)與SQL數(shù)據(jù)操作。壓縮包共128個(gè)文件以cs源碼文件為主輔以resx資源、resources編譯資源、jpg界面素材、exe可執(zhí)行程序及sln工程文件等整體約1.85MB目錄結(jié)構(gòu)清晰方便直接打開(kāi)編譯與二次修改。目前已有1437人學(xué)習(xí)/下載適合課程設(shè)計(jì)、畢業(yè)設(shè)計(jì)或項(xiàng)目實(shí)訓(xùn)參考。通過(guò)該項(xiàng)目可獲得整套窗體源碼、界面設(shè)計(jì)文件、數(shù)據(jù)庫(kù)交互邏輯及運(yùn)行程序覆蓋用戶(hù)模塊、車(chē)次管理模塊和訂單管理模塊的實(shí)現(xiàn)細(xì)節(jié)并包含常見(jiàn)錯(cuò)誤處理與異常捕獲寫(xiě)法可幫助讀者快速搭建同類(lèi)訂票系統(tǒng)提升C#與SQL Server的工程實(shí)踐能力。1. C#火車(chē)訂票系統(tǒng)不是查個(gè)數(shù)據(jù)庫(kù)那么簡(jiǎn)單C#火車(chē)訂票系統(tǒng)聽(tīng)起來(lái)就是把車(chē)次存進(jìn)數(shù)據(jù)庫(kù)、讓用戶(hù)查一查訂一訂但真正實(shí)現(xiàn)過(guò)的人都知道這個(gè)項(xiàng)目的核心難點(diǎn)根本不在增刪改查而在余票扣減的一致性?xún)蓚€(gè)用戶(hù)同時(shí)搶最后一張票系統(tǒng)憑什么只讓一個(gè)人成功訂單生成到一半網(wǎng)絡(luò)閃斷余票和訂單怎么保持一致說(shuō)到底訂票系統(tǒng)是一個(gè)典型的并發(fā)寫(xiě)密集型業(yè)務(wù)系統(tǒng)能用 C# 把它做扎實(shí)你對(duì)事務(wù)、鎖、連接池、異步 UI 的理解都會(huì)上一個(gè)臺(tái)階。這篇文章面向正在做課程設(shè)計(jì)的學(xué)生、想練手完整業(yè)務(wù)閉環(huán)的初級(jí)開(kāi)發(fā)者和需要把內(nèi)部訂票需求落地的工程師帶你從技術(shù)選型、數(shù)據(jù)庫(kù)設(shè)計(jì)一路走到并發(fā)壓測(cè)驗(yàn)證。2. 技術(shù)選型與三層架構(gòu)先決定系統(tǒng)長(zhǎng)什么樣再寫(xiě)代碼開(kāi)始寫(xiě)業(yè)務(wù)代碼之前先回答三個(gè)問(wèn)題系統(tǒng)給誰(shuí)用、部署在哪里、誰(shuí)來(lái)維護(hù)?;疖?chē)訂票系統(tǒng)在 C# 生態(tài)里有三種常見(jiàn)形態(tài)選型直接決定你后面要寫(xiě)多少界面代碼、能不能方便地?fù)Q數(shù)據(jù)庫(kù)、以及項(xiàng)目寫(xiě)到一半會(huì)不會(huì)因?yàn)榧軜?gòu)問(wèn)題返工。2.1 三種形態(tài)WinForms、WPF、ASP.NET Core 怎么選如果你做的是課程設(shè)計(jì)或公司內(nèi)部的小工具最常見(jiàn)的選擇是 WinForms。它拖控件就能出界面DataGridView 綁個(gè) DataTable 就能展示車(chē)次列表開(kāi)發(fā)速度最快答辯演示也直觀。缺點(diǎn)同樣明顯界面樣式老舊部署時(shí)目標(biāo)機(jī)器要裝對(duì)應(yīng)版本的 .NET Desktop Runtime而且窗體代碼很容易越寫(xiě)越臃腫最后 SQL 全部拼在按鈕點(diǎn)擊事件里調(diào)試一次要重啟一次窗口。如果你對(duì)界面有要求可以考慮 WPF。WPF 的綁定和樣式機(jī)制更適合做出復(fù)雜的座位選擇界面但 MVVM、依賴(lài)屬性、觸發(fā)器這些東西的學(xué)習(xí)成本對(duì)新手不太友好一個(gè)訂票系統(tǒng)的主要工作量會(huì)從業(yè)務(wù)邏輯轉(zhuǎn)移到界面框架上時(shí)間容易失控。如果想做一個(gè)真正能上線(xiàn)、手機(jī)和網(wǎng)頁(yè)都能訪(fǎng)問(wèn)的系統(tǒng)我建議選擇 ASP.NET Core WebAPI 加一個(gè)簡(jiǎn)單的前端頁(yè)面。這種形態(tài)沒(méi)有 WinForms 那樣的窗體生命周期業(yè)務(wù)層以 Controller 為入口天然適合對(duì)接小程序或網(wǎng)頁(yè)客戶(hù)端。缺點(diǎn)是得額外維護(hù)一套前端工作量會(huì)大不少。三者對(duì)比我一般這樣看形態(tài)適用場(chǎng)景界面開(kāi)發(fā)速度部署成本我的建議WinForms課程設(shè)計(jì)、內(nèi)部工具快拖控件即可需裝 Desktop Runtime練手首選WPF復(fù)雜界面、座位圖慢需先學(xué) MVVM需裝 Desktop Runtime對(duì) UI 有執(zhí)念再選ASP.NET Core WebAPI線(xiàn)上系統(tǒng)、多端訪(fǎng)問(wèn)需額外寫(xiě)前端只需 .NET Runtime簡(jiǎn)歷/生產(chǎn)推薦我的建議比較直接如果你的目標(biāo)是快速跑通整個(gè)業(yè)務(wù)閉環(huán)、把精力放在事務(wù)和并發(fā)上選 WinForms后面章節(jié)的代碼也按 WinForms 來(lái)寫(xiě)如果你是想拿這個(gè)項(xiàng)目做簡(jiǎn)歷上的代表作選 ASP.NET Core業(yè)務(wù)層代碼幾乎可以平移過(guò)去。還有一個(gè)隱藏因素?cái)?shù)據(jù)庫(kù)。WinForms 項(xiàng)目最常見(jiàn)的搭配是 SQL Server LocalDB 或 Express部署簡(jiǎn)單如果機(jī)器上沒(méi)裝 SQL Server也可以換成 SQLite但 SQLite 的并發(fā)寫(xiě)鎖比 SQL Server 嚴(yán)格得多后面章節(jié)講的并發(fā)方案要相應(yīng)調(diào)整。2.2 三層架構(gòu)拆分UI、BLL、DAL 的職責(zé)邊界不管選哪種界面形態(tài)我都強(qiáng)烈建議把項(xiàng)目拆成三層。一個(gè)典型的解決方案結(jié)構(gòu)是這樣TrainBooking.sln ├── TrainBooking.Model # 實(shí)體類(lèi)ScheduleInfo、OrderInfo ├── TrainBooking.DAL # 數(shù)據(jù)訪(fǎng)問(wèn)層只負(fù)責(zé) SQL 和數(shù)據(jù)庫(kù)交互 ├── TrainBooking.BLL # 業(yè)務(wù)邏輯層余票扣減、下單、退票規(guī)則 ├── TrainBooking.UI # WinForms 界面只負(fù)責(zé)展示和用戶(hù)輸入 └── TrainBooking.Common # 連接字符串、密碼哈希、訂單號(hào)生成等公共方法這樣拆有實(shí)打?qū)嵉暮锰?。第一業(yè)務(wù)規(guī)則可以單測(cè)。比如退票邏輯你不需要打開(kāi)窗體直接調(diào)用 BLL 的 CancelOrder 方法就能驗(yàn)證狀態(tài)流轉(zhuǎn)。第二換界面不換業(yè)務(wù)。昨天用 WinForms明天想改成 WebAPIUI 層扔掉BLL 和 DAL 原封不動(dòng)。第三連接字符串和 SQL 不會(huì)散落在各處換一臺(tái)數(shù)據(jù)庫(kù)服務(wù)器只改一個(gè)配置文件。我見(jiàn)過(guò)太多把數(shù)據(jù)庫(kù)操作直接寫(xiě)在 Form 里的項(xiàng)目一個(gè)按鈕點(diǎn)擊事件里幾百行代碼查詢(xún)、更新、彈窗全混在一起。分層之后DAL 只負(fù)責(zé)拿到參數(shù)、執(zhí)行 SQL、返回結(jié)果BLL 只負(fù)責(zé)判斷業(yè)務(wù)規(guī)則UI 只負(fù)責(zé)把用戶(hù)輸入傳給 BLL 再綁定結(jié)果。出了問(wèn)題可以按層排查界面表現(xiàn)異常查 UI業(yè)務(wù)規(guī)則不對(duì)查 BLL數(shù)據(jù)不對(duì)查 SQL不用再?gòu)膸资畟€(gè)事件方法里翻找。實(shí)體類(lèi)在 DAL 和 BLL 之間傳遞數(shù)據(jù)。以車(chē)次信息為例namespace TrainBooking.Model; public class ScheduleInfo { public int ScheduleId { get; set; } public string TrainNo { get; set; } string.Empty; public string StartStation { get; set; } string.Empty; public string EndStation { get; set; } string.Empty; public TimeSpan DepartTime { get; set; } public TimeSpan ArriveTime { get; set; } public byte SeatType { get; set; } public int RemainingCount { get; set; } public int TotalCount { get; set; } }這里 DepartTime 和 ArriveTime 用 TimeSpan 而不是 DateTime因?yàn)檐?chē)次表里存的是每天幾點(diǎn)發(fā)車(chē)這個(gè)重復(fù)性時(shí)刻不是某個(gè)具體時(shí)間點(diǎn)。很多初學(xué)者在這里用 DateTime后面查票時(shí)還得反復(fù)做日期拼接純屬給自己挖坑。連接字符串放在 Common 層的一個(gè)靜態(tài)類(lèi)里讀取 App.config 或 appsettings.json換服務(wù)器時(shí)只改一處。另外密碼不要在數(shù)據(jù)庫(kù)里明文存儲(chǔ)注冊(cè)時(shí)用加鹽哈希后存 Hash 列這是訂票系統(tǒng)的底線(xiàn)。.NET 的文檔不建議新代碼繼續(xù)用 MD5練手項(xiàng)目至少也得用 SHA256 加鹽比大部分課程設(shè)計(jì)已經(jīng)強(qiáng)了。三層架構(gòu)的代價(jià)是多寫(xiě)一層代碼但對(duì)訂票系統(tǒng)這個(gè)業(yè)務(wù)復(fù)雜度來(lái)說(shuō)這點(diǎn)代價(jià)非常值得。后面章節(jié)里所有代碼我都按這個(gè)分層來(lái)組織你可以在自己的項(xiàng)目里直接照抄這個(gè)結(jié)構(gòu)。3. 數(shù)據(jù)庫(kù)設(shè)計(jì)五張核心表與余票扣減的關(guān)鍵約束數(shù)據(jù)庫(kù)設(shè)計(jì)是訂票系統(tǒng)最容易返工的部分。返工不是因?yàn)楸聿粔蚨喽且驗(yàn)橐婚_(kāi)始沒(méi)想清楚余票這個(gè)數(shù)據(jù)模型。把余票拆成獨(dú)立的表而不是在車(chē)次表里放一個(gè) RemainingCount 字段這是整個(gè)設(shè)計(jì)的第一個(gè)關(guān)鍵決策。3.1 核心表結(jié)構(gòu)用戶(hù)、車(chē)次、排班、余票、訂單怎么建先看建表腳本我把一個(gè)最小可用的訂票系統(tǒng)拆成了五張表CREATE TABLE Users ( UserId INT IDENTITY PRIMARY KEY, Username NVARCHAR(50) NOT NULL UNIQUE, PasswordHash NVARCHAR(64) NOT NULL, -- 哈希后的密碼不存明文 RealName NVARCHAR(50) NOT NULL, IdCardNo NVARCHAR(18) NOT NULL ); CREATE TABLE Trains ( TrainId INT IDENTITY PRIMARY KEY, TrainNo NVARCHAR(20) NOT NULL UNIQUE, -- 車(chē)次號(hào)如 G1234 TrainType TINYINT NOT NULL, -- 1高鐵 2動(dòng)車(chē) 3普速 StartStation NVARCHAR(50) NOT NULL, EndStation NVARCHAR(50) NOT NULL ); CREATE TABLE Schedules ( ScheduleId INT IDENTITY PRIMARY KEY, TrainId INT NOT NULL REFERENCES Trains(TrainId), DepartDate DATE NOT NULL, -- 只存日期 DepartTime TIME NOT NULL, -- 每天的發(fā)車(chē)時(shí)刻 ArriveTime TIME NOT NULL, CONSTRAINT UQ_Schedule UNIQUE (TrainId, DepartDate) ); CREATE TABLE SeatInventory ( InventoryId INT IDENTITY PRIMARY KEY, ScheduleId INT NOT NULL REFERENCES Schedules(ScheduleId), SeatType TINYINT NOT NULL, -- 1二等座 2一等座 3硬臥 4軟臥 TotalCount INT NOT NULL, RemainingCount INT NOT NULL, CONSTRAINT UQ_Inventory UNIQUE (ScheduleId, SeatType) ); CREATE TABLE Orders ( OrderId INT IDENTITY PRIMARY KEY, OrderNo NVARCHAR(32) NOT NULL UNIQUE, -- 對(duì)外訂單號(hào) UserId INT NOT NULL REFERENCES Users(UserId), ScheduleId INT NOT NULL REFERENCES Schedules(ScheduleId), SeatType TINYINT NOT NULL, TicketCount INT NOT NULL, Status TINYINT NOT NULL DEFAULT 1, -- 1已支付 2已退票 3已過(guò)期 CreateTime DATETIME NOT NULL DEFAULT GETDATE(), CancelTime DATETIME NULL );有幾個(gè)設(shè)計(jì)點(diǎn)值得說(shuō)清楚。Trains 和 Schedules 分開(kāi)是因?yàn)橐惶肆熊?chē)如 G1234每天都在跑如果車(chē)次直接帶日期同一趟車(chē)每天都要復(fù)制一份始發(fā)站、終到站、車(chē)次號(hào)這些不變信息數(shù)據(jù)冗余而且改一個(gè)站名要改幾百行。Schedules 表用 (TrainId, DepartDate) 唯一約束從數(shù)據(jù)庫(kù)層面杜絕同一趟車(chē)同一天被重復(fù)錄入人工維護(hù)車(chē)次數(shù)據(jù)時(shí)這個(gè)約束特別有用。SeatInventory 是余票的核心。為什么單獨(dú)建表而不是在 Schedules 上掛一個(gè) RemainingCount因?yàn)橐惶塑?chē)有多種席別二等座、一等座、硬臥、軟臥的庫(kù)存互相獨(dú)立拆成行才能各自扣減、各自加鎖。RemainingCount 落在獨(dú)立的行上數(shù)據(jù)庫(kù)行鎖才能精確控制并發(fā)。Orders 表則承擔(dān)交易憑證的角色OrderNo 對(duì)外唯一客戶(hù)退款、改簽都靠這個(gè)號(hào)碼定位。索引方面查詢(xún)車(chē)次的典型條件是始發(fā)站、到達(dá)站、出發(fā)日期所以 Trains 加一個(gè) (StartStation, EndStation) 聯(lián)合索引Schedules 加一個(gè) DepartDate 索引Orders 的 OrderNo 已經(jīng)由 UNIQUE 約束自動(dòng)帶索引。如果用戶(hù)要查歷史訂單給 Orders.UserId 加一個(gè)非聚集索引否則按用戶(hù)查訂單會(huì)掃全表。3.2 余票扣減為什么先查再改一定會(huì)超賣(mài)余票扣減是訂票系統(tǒng)里最容易出事的一段代碼。新手最常見(jiàn)的寫(xiě)法是兩步走先 SELECT 余票判斷大于 0 再 UPDATE 減一。這個(gè)邏輯單用戶(hù)下沒(méi)問(wèn)題一旦兩個(gè)用戶(hù)同時(shí)買(mǎi)最后一張票就會(huì)同時(shí)讀到 RemainingCount 等于 1同時(shí)通過(guò)判斷同時(shí)執(zhí)行 UPDATE最終結(jié)果是兩個(gè)人下單成功余票變成 -1。這就是典型的超賣(mài)。正確的做法是讓扣減變成一個(gè)原子操作把判斷和更新合并到一條 SQL 里UPDATE SeatInventory SET RemainingCount RemainingCount - count WHERE ScheduleId scheduleId AND SeatType seatType AND RemainingCount count這條語(yǔ)句在 SQL Server 里執(zhí)行時(shí)會(huì)對(duì)命中的行加排他鎖兩個(gè)并發(fā)事務(wù)同時(shí)執(zhí)行時(shí)第二個(gè)事務(wù)會(huì)一直等到第一個(gè)提交或回滾然后重新讀取行數(shù)據(jù)發(fā)現(xiàn) RemainingCount 已經(jīng)不足更新影響行數(shù)為 0。代碼只需要判斷 ExecuteNonQuery 的返回值等于 0 就是庫(kù)存不足等于 1 才是扣減成功。這里有一個(gè)隱含的坑UPDATE 語(yǔ)句自帶鎖但 SELECT 和 UPDATE 分開(kāi)寫(xiě)的話(huà)SELECT 默認(rèn)不加排他鎖讀到的可能是已提交的舊值。所以要么像我上面這樣把判斷放進(jìn) UPDATE 的 WHERE要么給 SELECT 加 WITH (UPDLOCK) 提示強(qiáng)制加更新鎖。前者簡(jiǎn)單直接推薦優(yōu)先用。注意判斷余票是否扣減成功唯一可靠信號(hào)是 ExecuteNonQuery 的返回值不要依賴(lài)扣減前先查一次的舊值。返回值 0 時(shí)事務(wù)里后續(xù)步驟不應(yīng)繼續(xù)執(zhí)行必須回滾并返回失敗。另外一個(gè)容易被忽略的問(wèn)題是扣減順序。在一個(gè)訂單事務(wù)里先扣余票再插訂單比反過(guò)來(lái)的死鎖概率低。因?yàn)樗惺聞?wù)都按同樣的順序拿鎖就不容易出現(xiàn)兩個(gè)事務(wù)各自持有一把鎖又等對(duì)方釋放鎖的循環(huán)等待。記住這個(gè)原則多個(gè)資源要按固定順序加鎖。最后再加一道數(shù)據(jù)庫(kù)防線(xiàn)給 SeatInventory 建一個(gè)CHECK (RemainingCount 0)約束萬(wàn)一業(yè)務(wù)層有漏洞數(shù)據(jù)庫(kù)層面還能兜底這個(gè)約束的成本幾乎可以忽略。4. 核心功能落地查票、下單、退票的代碼實(shí)現(xiàn)這一章把三個(gè)核心業(yè)務(wù)操作完整寫(xiě)出來(lái)。代碼里用的都是 SqlClient 的同步方法WinForms 下我會(huì)在界面層用異步方式調(diào)用避免卡界面具體見(jiàn) 5.4 的坑。所有方法都按 BLL 層來(lái)設(shè)計(jì)不依賴(lài)任何控件類(lèi)型。4.1 查票參數(shù)化查詢(xún)與 DataTable 綁定查票接口的輸入是出發(fā)站、到達(dá)站、出發(fā)日期輸出是符合條件的車(chē)次和對(duì)應(yīng)席別余票。SQL 需要關(guān)聯(lián) Trains、Schedules、SeatInventory 三張表public DataTable QueryTickets(string fromStation, string toStation, DateTime departDate) { const string sql SELECT s.ScheduleId, t.TrainNo, t.StartStation, t.EndStation, s.DepartTime, s.ArriveTime, i.SeatType, i.RemainingCount FROM Schedules s INNER JOIN Trains t ON s.TrainId t.TrainId INNER JOIN SeatInventory i ON s.ScheduleId i.ScheduleId WHERE t.StartStation fromStation AND t.EndStation toStation AND s.DepartDate departDate ORDER BY s.DepartTime, i.SeatType; using var conn new SqlConnection(_connString); using var cmd new SqlCommand(sql, conn); cmd.Parameters.AddWithValue(fromStation, fromStation); cmd.Parameters.AddWithValue(toStation, toStation); cmd.Parameters.AddWithValue(departDate, departDate.Date); var adapter new SqlDataAdapter(cmd); var table new DataTable(); adapter.Fill(table); return table; }關(guān)鍵點(diǎn)有三處。第一所有查詢(xún)條件都用 SqlParameter 傳參絕不能拼字符串。拼字符串的后果是用戶(hù)輸入特殊內(nèi)容時(shí)SQL 語(yǔ)句被注入改寫(xiě)輕則查詢(xún)異常重則數(shù)據(jù)被刪。第二departDate 傳參前調(diào)用 .Date 把時(shí)分秒清零。如果界面用日期控件取到的值往往帶當(dāng)前時(shí)間直接用會(huì)導(dǎo)致 DepartDate 是 2024-05-01 00:00:00 但參數(shù)是 2024-05-01 14:30:00等值匹配永遠(yuǎn)查不到數(shù)據(jù)。第三函數(shù)返回 DataTable 是 WinForms 場(chǎng)景下的便捷做法直接賦值給 DataGridView.DataSource 就能顯示省去手工逐行賦值。有一個(gè)細(xì)節(jié)要提醒AddWithValue 在某些版本的 SQL Server 驅(qū)動(dòng)下可能把參數(shù)類(lèi)型推斷為 NVARCHAR導(dǎo)致查詢(xún)優(yōu)化器生成不了好的執(zhí)行計(jì)劃。如果你的系統(tǒng)數(shù)據(jù)量大、查詢(xún)慢可以改成顯式類(lèi)型聲明cmd.Parameters.Add(new SqlParameter(departDate, SqlDbType.Date) { Value departDate.Date });cmd.Parameters.Add(new SqlParameter(departDate, SqlDbType.Date) { Value departDate.Date });這個(gè)寫(xiě)法明確告訴數(shù)據(jù)庫(kù)參數(shù)是 DATE 類(lèi)型避免隱式轉(zhuǎn)換導(dǎo)致索引失效。項(xiàng)目規(guī)模小的時(shí)候不必較真但如果出現(xiàn)同一 SQL 每次都在編譯的現(xiàn)象先檢查這里。4.2 下單事務(wù)包裹的原子扣減與訂單生成下單是訂票系統(tǒng)的核心事務(wù)必須保證余票扣減和訂單插入要么一起成功要么一起回滾。我用 SqlTransaction 把兩步包起來(lái)public bool BookTicket(int userId, int scheduleId, byte seatType, int count, out string orderNo) { orderNo string.Empty; using var conn new SqlConnection(_connString); conn.Open(); using var tx conn.BeginTransaction(); try { // 第一步原子扣減余票扣不動(dòng)直接失敗 const string updateSql UPDATE SeatInventory SET RemainingCount RemainingCount - count WHERE ScheduleId scheduleId AND SeatType seatType AND RemainingCount count; using (var updateCmd new SqlCommand(updateSql, conn, tx)) { updateCmd.Parameters.AddWithValue(count, count); updateCmd.Parameters.AddWithValue(scheduleId, scheduleId); updateCmd.Parameters.AddWithValue(seatType, seatType); if (updateCmd.ExecuteNonQuery() 0) { tx.Rollback(); return false; // 余票不足或車(chē)次不存在 } } // 第二步生成訂單號(hào)插入訂單 orderNo GenerateOrderNo(); const string insertSql INSERT INTO Orders (OrderNo, UserId, ScheduleId, SeatType, TicketCount, Status) VALUES (orderNo, userId, scheduleId, seatType, count, 1); using (var insertCmd new SqlCommand(insertSql, conn, tx)) { insertCmd.Parameters.AddWithValue(orderNo, orderNo); insertCmd.Parameters.AddWithValue(userId, userId); insertCmd.Parameters.AddWithValue(scheduleId, scheduleId); insertCmd.Parameters.AddWithValue(seatType, seatType); insertCmd.Parameters.AddWithValue(count, count); insertCmd.ExecuteNonQuery(); } tx.Commit(); return true; } catch { tx.Rollback(); throw; } }這段代碼有兩個(gè)重要設(shè)計(jì)。第一扣減余票和插入訂單共用同一個(gè)連接和同一個(gè)事務(wù)這是為了保證一致性。如果不用事務(wù)扣減成功但插入訂單時(shí)斷電余票就莫名其妙少了反過(guò)來(lái)訂單插入成功但扣減失敗就會(huì)出現(xiàn)空頭訂單。第二余票扣減放在事務(wù)最前面所有請(qǐng)求都按同一順序拿鎖降低死鎖概率。ExecuteNonQuery 返回 0 時(shí)立即回滾返回 false調(diào)用方可以提示余票不足。注意這里把支付和下單合并成一步是為了聚焦庫(kù)存一致性。真實(shí)系統(tǒng)通常先建待支付訂單支付回調(diào)確認(rèn)后再把狀態(tài)改成已支付。那個(gè)狀態(tài)流轉(zhuǎn)的原則與此處完全一致——狀態(tài)更新必須帶當(dāng)前狀態(tài)條件。訂單號(hào)的生成方法我一般這樣寫(xiě)private static string GenerateOrderNo() { var now DateTime.Now; return now.ToString(yyyyMMddHHmmssfff) Random.Shared.Next(1000, 9999); }時(shí)間戳加隨機(jī)數(shù)的組合在演示項(xiàng)目里夠用但你要知道它的局限同一毫秒內(nèi)多個(gè)請(qǐng)求理論上有碰撞可能。生產(chǎn)環(huán)境我建議用全局自增序列或 Redis INCR 生成訂單號(hào)避免撞號(hào)或者干脆讓數(shù)據(jù)庫(kù)自增主鍵對(duì)外暴露雖然不好看但保證唯一。4.3 退票狀態(tài)守衛(wèi)與余票回補(bǔ)退票比下單容易但同樣有陷阱。最常見(jiàn)的錯(cuò)誤是直接 UPDATE Orders SET Status 2 然后回補(bǔ)余票完全沒(méi)有檢查訂單當(dāng)前狀態(tài)。如果用戶(hù)把退票請(qǐng)求發(fā)兩次或者管理端代退后用戶(hù)自己又退了一次余票會(huì)被回補(bǔ)兩次系統(tǒng)里憑空多出票來(lái)。正確的退票要先做狀態(tài)守衛(wèi)只允許把已支付的訂單改成已退票public bool CancelOrder(string orderNo) { using var conn new SqlConnection(_connString); conn.Open(); using var tx conn.BeginTransaction(); try { // 第一步狀態(tài)守衛(wèi)只有 Status 1 的訂單能退 const string updateOrderSql UPDATE Orders SET Status 2, CancelTime GETDATE() WHERE OrderNo orderNo AND Status 1; int affected; using (var cmd new SqlCommand(updateOrderSql, conn, tx)) { cmd.Parameters.AddWithValue(orderNo, orderNo); affected cmd.ExecuteNonQuery(); } if (affected 0) { tx.Rollback(); return false; // 訂單不存在或已處于不可退狀態(tài) } // 第二步按訂單的席別和數(shù)量回補(bǔ)余票 const string restoreSql UPDATE i SET i.RemainingCount i.RemainingCount o.TicketCount FROM SeatInventory i INNER JOIN Orders o ON i.ScheduleId o.ScheduleId AND i.SeatType o.SeatType WHERE o.OrderNo orderNo; using (var cmd new SqlCommand(restoreSql, conn, tx)) { cmd.Parameters.AddWithValue(orderNo, orderNo); cmd.ExecuteNonQuery(); } tx.Commit(); return true; } catch { tx.Rollback(); throw; } }UPDATE Orders 的 WHERE 條件里帶 Status 1 就是冪等守衛(wèi)。第一次退票成功訂單狀態(tài)變成 2第二次執(zhí)行同樣的語(yǔ)句WHERE 匹配不到行影響行數(shù)為 0直接返回失敗余票也不會(huì)二次回補(bǔ)。這個(gè)模式在支付回調(diào)、退款、改簽等所有狀態(tài)流轉(zhuǎn)場(chǎng)景里都適用?;匮a(bǔ)余票的 SQL 用 UPDATE FROM JOIN 語(yǔ)法從 Orders 中取回 TicketCount 和 SeatType與 SeatInventory 按 ScheduleId 和 SeatType 關(guān)聯(lián)。注意賦值方向左邊 RemainingCount 加的是訂單里的票數(shù)而不是固定加 1。一張訂單可能包含多張票按固定值回補(bǔ)必然出錯(cuò)。5. 踩坑與排查訂票系統(tǒng)最容易翻車(chē)的五個(gè)場(chǎng)景這一章整理的是我在類(lèi)似項(xiàng)目里真實(shí)踩過(guò)、也幫別人排查過(guò)的五個(gè)高頻問(wèn)題。每一個(gè)都按現(xiàn)象 → 原因 → 解決三段式展開(kāi)你可以直接對(duì)照排查。5.1 并發(fā)超賣(mài)最后一張票被賣(mài)給了三個(gè)人現(xiàn)象用多線(xiàn)程模擬 50 個(gè)用戶(hù)同時(shí)搶同一車(chē)次的最后 1 張票數(shù)據(jù)庫(kù)里出現(xiàn)了多張成功訂單余票變成負(fù)數(shù)。原因業(yè)務(wù)代碼先 SELECT 余票再 UPDATE兩個(gè)請(qǐng)求同時(shí)讀到余票為 1同時(shí)通過(guò)判斷各自生成訂單。這是典型的檢查與動(dòng)作分離導(dǎo)致的競(jìng)態(tài)條件。解決把判斷合并進(jìn) UPDATE 語(yǔ)句用影響行數(shù)判斷是否成功代碼見(jiàn) 4.2 的 BookTicket。另外給 SeatInventory 建CHECK (RemainingCount 0)約束作為最后一道防線(xiàn)萬(wàn)一業(yè)務(wù)層有漏洞數(shù)據(jù)庫(kù)層面還能兜底。這個(gè)約束成本極低強(qiáng)烈建議加上。5.2 連接池耗盡只 Open 不 Dispose 的后果現(xiàn)象程序運(yùn)行一段時(shí)間后操作數(shù)據(jù)庫(kù)時(shí)報(bào)錯(cuò)連接池已滿(mǎn)或超時(shí)時(shí)間已到尚未從池中獲取連接。原因SqlConnection 打開(kāi)后沒(méi)有釋放。連接池默認(rèn)最大連接數(shù)是 100每次連接用完后如果只是 Close 而沒(méi)有 Dispose異常路徑提前 return 時(shí)連接就永遠(yuǎn)留在池里很快把連接池占滿(mǎn)。解決所有 SqlConnection 的創(chuàng)建一律用 using 聲明。C# 的 using 會(huì)自動(dòng)調(diào)用 Dispose等價(jià)于把連接歸還連接池。如果項(xiàng)目里有手寫(xiě) DBHelper 的老代碼見(jiàn)到 new SqlConnection 后面沒(méi)有 using 或沒(méi)有 Close 的一律改掉。這是一個(gè)可以在代碼評(píng)審時(shí)快速核查的點(diǎn)用一個(gè)正則就能掃出來(lái)。5.3 日期格式化陷阱查當(dāng)天車(chē)票卻查不到現(xiàn)象用戶(hù)在界面上選了 2024-05-01查詢(xún)結(jié)果為空但數(shù)據(jù)庫(kù)里明明有當(dāng)天車(chē)次。原因最常見(jiàn)的是參數(shù)類(lèi)型不匹配。日期選擇控件的值帶時(shí)分秒比如 2024-05-01 14:30:00而 Schedules.DepartDate 列是 DATE 類(lèi)型等值比較時(shí)數(shù)據(jù)庫(kù)把參數(shù)隱式轉(zhuǎn)換實(shí)際變成 2024-05-01 00:00:00 與 2024-05-01 14:30:00 比較自然不相等。解決傳入?yún)?shù)前統(tǒng)一使用 departDate.Date 把時(shí)間清零參數(shù)顯式聲明為 SqlDbType.Date。查詢(xún)條件堅(jiān)持用參數(shù)化不要日期 ToString 后拼進(jìn) SQL。遇到當(dāng)天查不到但前一天能查到的詭異問(wèn)題第一反應(yīng)就去看日期參數(shù)的值十有八九是這里。5.4 UI 線(xiàn)程假死同步查詢(xún)阻塞窗口現(xiàn)象點(diǎn)擊查詢(xún)按鈕后窗口標(biāo)題出現(xiàn)未響應(yīng)過(guò)幾秒才恢復(fù)期間窗口無(wú)法拖動(dòng)、無(wú)法關(guān)閉。原因WinForms 的按鈕點(diǎn)擊事件跑在 UI 線(xiàn)程上同步執(zhí)行數(shù)據(jù)庫(kù)查詢(xún)時(shí)UI 線(xiàn)程被阻塞消息循環(huán)無(wú)法處理重繪和鼠標(biāo)消息。數(shù)據(jù)量一大阻塞時(shí)間就越明顯。解決把數(shù)據(jù)庫(kù)調(diào)用放到后臺(tái)線(xiàn)程用 async/await 回到 UI 線(xiàn)程更新界面private async void btnQuery_Click(object sender, EventArgs e) { btnQuery.Enabled false; try { var from txtFrom.Text.Trim(); var to txtTo.Text.Trim(); var date datePicker.Value.Date; var table await Task.Run(() _ticketService.QueryTickets(from, to, date)); dataGridView1.DataSource table; } catch (Exception ex) { MessageBox.Show(查詢(xún)失敗 ex.Message); } finally { btnQuery.Enabled true; } }這里用到 Task.Run 把同步的 DAL 方法丟到線(xiàn)程池執(zhí)行await 之后自動(dòng)回到 UI 線(xiàn)程更新 DataGridView。按鈕在查詢(xún)期間禁用避免用戶(hù)重復(fù)點(diǎn)擊疊加請(qǐng)求。注意async void 只能用在事件處理器這類(lèi)沒(méi)有調(diào)用方的場(chǎng)景普通方法一律返回 Task否則異常會(huì)直接逃逸到同步上下文導(dǎo)致進(jìn)程崩潰。5.5 重復(fù)下單雙擊一次生成兩個(gè)訂單現(xiàn)象用戶(hù)雙擊確認(rèn)按鈕或者網(wǎng)絡(luò)慢時(shí)連點(diǎn)多次數(shù)據(jù)庫(kù)里同一個(gè)用戶(hù)對(duì)同一個(gè)車(chē)次生成了兩條訂單。原因按鈕點(diǎn)擊事件沒(méi)有防重后端也沒(méi)有冪等判斷。前端禁用按鈕只能擋住正常人擋不住雙擊事件和網(wǎng)絡(luò)重試。解決前端在提交后立即禁用按鈕同時(shí)在數(shù)據(jù)庫(kù)層面加一道唯一約束。下單前由調(diào)用方生成一個(gè)請(qǐng)求標(biāo)識(shí)Orders 表增加 RequestId 列并建唯一索引第一次插入成功第二次插入同樣的 RequestId 會(huì)因?yàn)槲ㄒ患s束被拒。事務(wù)里可以先查這個(gè) RequestId 是否已存在存在就直接返回已有訂單不存在才走完整的扣減流程。雙重防護(hù)之下重復(fù)點(diǎn)擊的后果被徹底堵死。6. 并發(fā)壓測(cè)驗(yàn)證你的余票扣減真的不會(huì)超賣(mài)寫(xiě)完了業(yè)務(wù)代碼不能直接就說(shuō)系統(tǒng)沒(méi)問(wèn)題。訂票系統(tǒng)這種并發(fā)業(yè)務(wù)驗(yàn)證手段就是模擬大量用戶(hù)同時(shí)搶票看最終訂單數(shù)和余票數(shù)是否對(duì)得上。我會(huì)寫(xiě)一個(gè)小的控制臺(tái)壓測(cè)程序直接調(diào)用 BLL 層的方法繞開(kāi) UIstatic async Task Main(string[] args) { var service new TicketService(your_connection_string); // 假設(shè)數(shù)據(jù)庫(kù)里某車(chē)次 ScheduleId1001SeatType1RemainingCount1 const int userId 1; const int scheduleId 1001; const byte seatType 1; int success 0, fail 0; var tasks new ListTask(); for (int i 0; i 200; i) { tasks.Add(Task.Run(() { bool ok service.BookTicket(userId, scheduleId, seatType, 1, out _); if (ok) Interlocked.Increment(ref success); else Interlocked.Increment(ref fail); })); } await Task.WhenAll(tasks); Console.WriteLine($成功 {success}失敗 {fail}); }這個(gè)壓測(cè)有幾個(gè)要點(diǎn)。第一200 個(gè)任務(wù)并發(fā)調(diào)用同一個(gè) BLL 方法直接測(cè)核心事務(wù)邏輯不摻雜界面因素。第二使用 Interlocked 累加結(jié)果因?yàn)?int 的 在并發(fā)下不是原子的直接寫(xiě) success 統(tǒng)計(jì)會(huì)丟數(shù)據(jù)。第三壓測(cè)前手動(dòng)把余票改為 1壓測(cè)后驗(yàn)證成功數(shù)是否恰好為 1。如果成功數(shù)大于 1說(shuō)明你的扣減邏輯還有競(jìng)態(tài)條件回到 3.2 檢查。壓測(cè)結(jié)果正常后再進(jìn)一步觀察鎖等待。在 SQL Server 上執(zhí)行 sp_who2 或查看 sys.dm_tran_locks確認(rèn)同一時(shí)刻只有少量會(huì)話(huà)處于等待鎖狀態(tài)。如果等待會(huì)話(huà)特別多說(shuō)明事務(wù)持有鎖的時(shí)間過(guò)長(zhǎng)優(yōu)先檢查 4.2 里事務(wù)內(nèi)有沒(méi)有多余的查詢(xún)操作把查詢(xún)移出事務(wù)能顯著縮短持鎖時(shí)間。對(duì)于更高要求的場(chǎng)景可以再用 WITH (UPDLOCK) 寫(xiě)一個(gè)備用方案事務(wù)內(nèi)先 SELECT 余票并加更新鎖阻塞其他事務(wù)的更新直到當(dāng)前事務(wù)結(jié)束然后再做業(yè)務(wù)判斷和 UPDATE。它適合業(yè)務(wù)判斷比較復(fù)雜、沒(méi)法塞進(jìn)一條 UPDATE 的場(chǎng)景代價(jià)是持鎖時(shí)間更長(zhǎng)。我的習(xí)慣是能用原子 UPDATE 就用原子 UPDATEUPDLOCK 只做兜底。壓測(cè)做到這個(gè)程度你的訂票系統(tǒng)在并發(fā)扣減這一關(guān)就站得住腳了。我自己的習(xí)慣是把這個(gè)壓測(cè)代碼留在項(xiàng)目里每次改完數(shù)據(jù)庫(kù)或事務(wù)邏輯就跑一遍余票從 1 變成 0、成功數(shù)永遠(yuǎn)是 1才敢放心把系統(tǒng)交給業(yè)務(wù)方使用。寫(xiě)代碼容易真正讓人放心的是驗(yàn)證過(guò)邊界條件的代碼。希望這篇筆記能幫你把 C# 火車(chē)訂票系統(tǒng)做扎實(shí)也少走我當(dāng)年走過(guò)的那些彎路。本文還有配套的精品資源點(diǎn)擊獲取
返回列表
PREV
查看更多資訊
NEXT
返回資訊列表
日韩无码精品综合久久| 国产精品久久99日日| 婷婷五月丁香五月| 日本性爱欧美性爱| 国产精品另类一区大香蕉| 一级黄色影片| 久久鲁干| 国产资源中文字幕在线| 亚洲人久久久网| 欧亚在线视频| 国产精品久久久久久久久久久久久久吹 | 九九久久精品| 精品人妻中文字幕4399| 欧美色视| 高清无码91| 东京热精品97综合网| 国产欧美日韩在线不卡第一页| 男人的天堂久久久| 精品综合久久久久久97| AV天堂男人的天堂| 亚洲熟妇自偷自拍另欧美| www国产无码| 久久精品99| 97硬碰| 久久99久久99久久99人受| 亚洲高清综合网| 伊人四虎综合| 在线黄色污污网站| 亚洲成人一二三区| 九九热免费在线国产视频伊人五月| 另类 日韩 熟女| 午夜乱轮操逼视频免费看| 国产日韩怡红院| 国语对白露脸XXXXXX| 97天天综合网| 中文字幕一区av| 可能人人看人人摸| 人妻精品一区二区在线| 成人精品一区二区91毛片不卡| 久草看看看| 97网址97| 欧美性视频二区三区| 97香蕉人人乳| 欧美97在线观看| 美女尤物福利视频| 久久久精品日本一道| 综合五月天| 国产精品视频精品一二| 国产亚洲日本精品在线| 亚洲成a人片在线观看中文!!!| 玖玖爱影院| 精品中文一区二区| 久久机热| 激情文学亚洲| 亚洲丝袜少妇在线| 精品视频一区二区| 一区二区三区四区免费视频| 家庭乱伦网站国产| 婷婷激情综合网| 久久精品亚洲成a人天堂| 亚洲最大成人a毛毛片| A级国产欧美激情在线| 日本成a人v网站在线观看| 麻豆精品.欧美精品.日韩精品.| 粉嫩av一区二区三区四季| 日韩资源网| 激情综合色| 夜夜嗨AV蜜臀av| 一道本东京热加勒比一区二区三区| 人妻天天爽夜夜爽精品2| 91在线丝袜视频| 日韩中文9| 久久久久久久六六 | 精品免费成人久久| 啊啊啊好舒服视频| 无码高清专| 97视频观看| 97硬碰| 91欧美少妇| 婷婷激情四射| 秋霞视频一区二区| 84YTCOM性无码| 国产91福利小视频在线观看| 国产亚洲女v在线观看| 思思热久久成人| A片 AV一级在线播放观看免费| a级成人毛片免费视频高清| AV和黑人在线播放| 亚洲人妻av| 日本九九久久99播| 国产嫩草精品A88AV| 97精品免费视频网站| 国产无吗在线播放| 日本护士高潮| 免费国产| 亚洲欧美综合| 激情综合久久| 91AV国产精品| 亚洲一区在线观看欧洲| 激情丁香五月婷婷| 伊人久久大香线蕉亚洲五月天,青草青草欧美日本一区二区,欧美日产欧美日产国产 | 久久精品无码熟妇一区二区三区视频导航 | 色噜噜狠狠色综合日日| 亚洲免费97免费| 国产日韩中文字幕欧美| 强奸乱伦大香蕉| 丝袜美腿诱惑亚洲欧美视频在线观看| ...日韩成人一区二区三区字幕| 99999国产| av绯色| 蜜乳AV色欲AVAV无码| 成人贴图日韩欧美| 中文字幕乱妇免费视频| 国产乱伦亚洲| 黄总AV色图| www.91视频网| 国产精品无码AV网站| 九九九九88| 天天日天天干少妇日| 国模精品一区二区三区苹果色戒| 97网址97| www.超碰| 欧美图片校园春色| 在线可观看的黄色网址| 97精品久久久久中文字幕| 91久久青青草原精品| 久久婷婷色| 亚洲AV在线资源| 操啊国产| 欧美一区二区情色| 自怕偷自怕亚洲精品| 九九精品美女高溯喷水| 日本国产高清色www视频在线| 精品超碰国产| 97视频新免费| 99爱视频| 高清无码在线播放网站| 动漫区日韩区欧美区| 日韩欧美亚洲自拍偷拍| 少妇被玩视频二三区| 欧美AB在线| 人妻啊啊人妻啊啊| 天天视频黄| 91亚洲影院综合| 襙一襙| 歐美性天天| 超碰97人人cao| 性生活无遮挡纯毛片在线看| 丰满岳乱妇一区二区三区| 人人操天天爽| 成人AV超碰免费在线| 东京热一区二区三区四区五区六区| 伊人网高清| 婷婷香蕉欧美在线一区二区三区| 91操操操操| 95精品在线| 中文一区二区三区影院| 久久久久久久久久久精| 国产日本熟女顶级一区二区三区视频 | 久区视频| 久久九七| 国内三级自拍小视频在线观看| 欧美黑人日韩少妇色情| 另类图片五月| 97色综合中文网| 狠狠干综合| 午夜小电影在线插入淫高潮| 亚洲AV色图一区| 99精品视频在线观看| 亚洲国产精品无石码久久| 欧美黄色图片| 丁香五月天激情| 亚洲av噜噜噜噜噜噜| 国产乱弄免费在线视频。| 亚洲无码久久久久久久| 农村女一级毛卡片| 欧美姓爱综合网| 青青草亚洲一区| 韩国午夜理伦三级好看| 日韩亚洲欧美中文字幕| 欧美与日韩97| 欧美老妇综合网| A片三级无码| 欧美综合另类| 伊人亚洲综合| 成人欧美一区二区三区黑人一| 国产熟女一区二区| 久久久久9999精品九九九| 五月婷婷久久综合| 伦伦成年午夜免费视频| 久久久久久九九九| 91色综合色| 情色日播放AV| 操一区| 欧美自拍偷拍综合图片| 91国产丝袜白虎| 亚洲一区二区三区麻豆传媒| 99re6久热只有精品6在线直播| 青娱乐福利99| 亚州一区二区| 一区二区三区一亚洲中文字幕、综合区灬| 欧美视频第二页| 国产欧美日韩女同性恋ww喷水精品| 影音先锋少妇| 97久久网| 久久久久夜夜夜夜| 3P丝袜熟女 色综合| 欧美性综合| 高树玛利亚无码流出| 99热伊人| 人妻少妇久久久| 亚洲97久久精品亚洲| 久久精品 六十路 熟女 欧美| 啊啊啊好大好深| 欧美在线干| 久久伊人青青草| 大香蕉 222| baisiav| 国产伦精品一区二区三区视频女| 婷婷91| 国产a级午夜毛片| 极品国产内射| 美女裸体无遮挡永久免费观看网站| 免费操逼91| 超碰97丝袜| 97视频在线免费| 青久久| 超碰97久久国| 97在线免费视频观看| 热热色AV| 欧美在线亚洲| 射综合网| 男女啪啪网站免费视频| 成人免费福利在线观看| 国产热RE99久久6国产精品首| 亚洲中文日韩欧美大香蕉视频| 国产成人一级av88| 国内毛片免费h片在线| 亚洲成人综合在线| 国产精品久久久亚洲一区| 色蜜AV| 色一射色一射| 91综合国产精品| 亚洲综合九| ...日韩成人一区二区三区字幕| 蜜臀久久99'精品久久久| 欧亚日本情色| 五十路熟女人妻一区二区三区四区五| 91福利网在线观看| 日韩精品 视频一区二区| 日韩黄色一区二区三区| 女人的久久久| 一二三四视频在线社区中文字幕| 久久久久幕乱码| 91精品人妻一品二品三品| 亚洲色图图片| 国产女人高潮嗷嗷嗷叫小说 | 日日狠狠久久偷偷色综合免费| 亚洲天堂中文字幕无码男同| 99精品久久久久久| 97国产人人| 蜜乳Av成人片网站| 在线无码操| 韩日自拍| 成人五级久久| 欧洲精品一级二级精品综合视频综合| 久久草草亚洲蜜桃臀| 一级做受视频免费是看美女| 精品人妻av在线播放| 欧美性爱另类综合| 国产日韩欧美| 中字幕人妻一区二区三区| 日本免费一区二区不卡 | 精品午夜福利国产一区二区在线观看| 精品高清一区二区三区三州| 五月婷婷激情网| A啊啊在线观看| AV女优男人的天堂| 高清国产性猛交xxxx乱大交| 97精品国产97久久久| 精品一二三区四视频| 国产综合久久久麻桃个| 国产一区二区精品久久99| 日本免费中文一区二区三区四区| 91在线国产后入风骚翘臀美女素人| 国产精品片| 五月天玖玖资源站| 91国内外在线| 操操吧亚洲乱伦视频| 国产精品一二三区福利| 欧美综合色综合| 日韩字幕一区| 亚洲综合色男人网| 青青在线视频免费| 免费看欧美美女黄色大片| 久久综合女优| 思思视频免费看网站| 另类图片五月天| 欧美在线视频播放| 夜夜天天噜狠狠爱2021| 91jk色拍| 久久亚州精品成人Av无| 97色视频在线| 亚洲一区二区三区在线激情| 国产日韩精品一区二区三区| 人妻久久一区二区三区 | 久久日本熟女精品一区| 日韩欧美性吧婷婷乱伦大香蕉| 97色干| 91蜜桃传媒精品久久久一区二区| 日本在线视频导航| 日韩有码回春沙龙第一页| 日韩人妻播放| 九七毛片九九毛片| 久久婷婷伊人| 亚洲欧洲成人在线电影| 校园春色亚洲欧洲| 情趣丝袜无码操逼视频| 一区二区三区成人 | 色哟哟的毛片| 97视频网站| 女优免费一区二区永久| 操国产高清| 性欧美天天| 成年人网站在线免费观看| 激情四射婷婷四五月天| 国产1024在线播放| 视频黄站| 91人妻人人妻| 国产AV色黄看到爽| 性九九九九九九| 婷婷伊人网| 中文字幕一二三| 歐美一級亂黃99在綫精品| 老司机天天操| 日韩中文9| 亚洲欧美国产其他二区| 九久精品| 一二视频神马久久传媒| 久热无码| 先锋激情∨在线视频播放| 日韩精品大香蕉伊人在线| 操逼网站视频漫画国产| 国产一区二区在线播放| 久久仑合| 99热只有这里有精品| 精品少妇高潮久久| 秋霞一区二区三区四区五区六区七区| 91人妻素女| 综合第一页| 久久久中文版| 日韩无码专区| 精品成人动漫一区二区| 99re在线| 黄色一区三区| 欧美色图亚洲特色| 91粉嫩萝控精品福利网站_精品影音先锋国 | 高树玛利亚无码流出| 丰满人妻无码一区二区三区| 999久久久九九九九| caopeng97人妻| 无码抄逼网| a片在线播放| 欧美自拍网| 久久精品小视频| 三级特黄60分钟播放| 天堂网亚洲区手机版| 青青草啪啪网| 免费看美国人人爽,人人操| 国产精品久久久久中文字幕| 韩日色费| 亚洲欧洲成人在线电影| 亚洲精品久久久久久久蜜桃臀| 操一区| 啊啊啊啊啊在线观看网址| 欧美网站免费| 欧美日韩岛国大片在线观看| 97超碰人人模人人拍人人| 欧美在线第五页| 亚洲欧洲久久天堂| 久久av色| 丝袜综合色图| 欧美72网页| 1024久久高清视频| 欧美嗯啊……在线观看视频免费| 狠狠综合| 中文字幕一区日韩精| 美女写真| www.大香| 国产美女高潮叫床视频| 精品亚洲国产成人精品| 精品无码久久久久久国产浪潮| 99无码| 久久精品28| 蜜臀99久久精品久久久久久| 亚洲AV永久无码精品成人调教| 一区二区视频你懂的| 欧美综合第一| 99re69综合| 国产精品 午夜福利| 国产精品2020| 久久久久久波多野吉衣高潮| 老熟妇综合| 鸥美插入视频| 欧美精品91| 午夜精品久久久久久久99热影院 | 激情综合网亚洲| 中文字幕久久精品一区| 日本亚洲熟女视频| 九九伊人网| 永久电影三级在线观看| 啊啊啊啊啊啊啊在线| 无套内射性感少妇视频| 97 亚洲 日韩 欧美 在线| 三级特黄60分钟播放| 秋霞成人一级在线观看| 欧美日韩性爱无码| 99re久久| 97午夜剧场日韩| 欧美性后入| 人人人人人人少妇| 97 国产一区| 2017大香蕉国产精品久久| 久操网在线| 麻豆区久久久久亚| 91综合网| 亚洲免费在线探花| 动漫爆乳3D奶水一区在线观看| 在线观看日韩av不卡| 成人av免费观看| 91黑丝在线播放| 综合婷婷| 情色五月天久久久| 国产精品夜夜夜| 九九亚洲| 日本性爱网址| 97色色网| 操死我了啊啊啊| 综合色久欲| 日语五十路和六十路亚洲国产精品| 伊人网青青| 久操不卡视频| 神马久久久久久久久久| 美女91网| 这里只有精品视频在线观看麻豆| 制服乱伦| 丰满人妻一区二区中文| 婷婷操视频| 3p国产色噜噜一区| 亚洲va综合va国产va中文| 亚洲日韩青青草色月| 天天综合,91入口| 内射老妇BBWX0C0CK| 717影院理论午夜伦八戒| 久久综合九九| 91在线国产后入风骚翘臀美女素人| 欧美91变态| 91操人| 亚洲成av人片色午夜乱码| 美女啊啊啊啊pc| 91制服丝袜| 国产精品欧美日韩久久| 抽插爽| 不卡六六在线91| 日韩偷拍一区二区三区| 亚洲天堂区| 五月天久久人妻| 日韩中文字幕人妻视频| 免费视频在线观看啊啊啊啊啊| 少妇熟女视频一区二区三区| 无码高清国产AV| 欧美超碰96| 国产精品精品系列在线观看| 东京热亚洲一区二区| 偷拍超碰| www.伪伪| a片亚洲一本通视频| 日韩免费簧片| 成人丁香五月| 亚洲一区中文字幕| 97色色视频| 国产精品另类| 久碰视频| 72av视频| 天美传媒国产原创中文字幕亚洲欧美另类| 久久婷婷一区| 久久香蕉影院| 亚洲双插| 后X久久| 国产女同在线观看视频| 91丨国产丨白浆| 好吊色综合| 人妻熟女一区在| 亚洲天堂男人天堂网| 色婷婷丁香五月| 尤物AV免费网站| 日本精品第一视频在'| 97在线播放| 色色五月天激情| 男人的天堂VA| 黄色二级片网站| 国产精品白丝在线播放| 久久综合女优| 中文字幕日本久久| 午夜αv| 色一射色一射| 免费一级a毛片久久久久久鸭绿欲| 色九九九综合| 色牛牛AV| 囯产精品久久久久久久久久梁医生| 毛片17S| 自拍偷拍第26| 亚洲天堂日本| 欧美综合骚| 亚洲精品尤物yw在线影院| 北条麻妃性愛视频| 99综合视频一体| 色综合一本| 自拍亚洲综合| 日韩AV电影网站| 蜜乳成人AV| 91在线丝袜| 射 色综合| 眼镜人妻101.com| 青青草华人在线欧美在线| 成年女人18级毛片毛片免费观看| 久久午夜色播影院免费高清| 91天射| 久久国内| 欧美日韩黄片精品在线| 亚洲性刺激| 猛交交| 秋霞影音一区二区三区| 欧美亚洲图片| 熟女熟妇一区二区三区视频| 午夜久久一区二区无码中出| 中国东北熟女老太婆内谢| 欧美双插| 国产精品高朝久久久久久久| 啪啪视频mP4| 国产自产自拍| 亚洲啪啪视频免费| 欧美瑟综合| 啊啊啊 在线观看| 伊人久久大香大香线蕉中文 | 亚洲色宗合| 啊啊啊要高潮了| AV天天在线观看| 久久国内| 亚洲国产尤物yw在线观看| 91丝袜视频在线观看| 午夜后入| 久久精品老司| 大香蕉在线视频15| 午夜天堂精品久久久久91| 熟女精品va中文字幕| 免费久久一级毛片大黄| 亚洲色婷婷久久久综合日本| 成人情色综合网| 久久精品中文| 久久久久久91香蕉国产| 久久欧美1卡2卡3| 亚洲性爱无码乱伦av| 99久国产精品午夜性色福利| 久久久极品| 福利天天都操| 久久超碰大香蕉| 和协无码影院| 超碰97在线 欧美 国产| 91+欧美| 高树玛利亚无码流出| 97资源超碰| 99热这里只有精| 久久免费老司机精品| 四虎AV在线观看| 五月激情综合网| 天天插天天射| 中文无码一二三区| 综精品久久久aaaa| 欧洲射精91| 超碰97资源大奶| 亚洲国产综合久久天堂| 99操| 60秒免费视频| 97中文字幕一区| 毛片99-全集电影手机免费观看完整-B029AV| 人妻精品综合中文字幕在线| 思思热在线| 麻豆AV一区二区| 亚洲网自拍| 久草精品一区| 久久国产精品熟女人妻| 久久久久久久久久久久九| 久久精品成人一区二区三区蜜臀| 国产精品粉嫩福利在线| 阿姨一区二区免费视频-高清正片西瓜视频下载app-T450AV | 亚洲中文字幕av| 色色九区| 丝袜 中出 制服 人妻 美腿 中文字幕| 久久久久国色αv免费观看| 十八禁电影伊人网| 97碰碰色| 久久噜| 9久热这里只有精品| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区老师黑人潮喷一 | 老子午夜伦不卡影院| 亚洲 欧美 手机在线观看| 欧美激情综合| 色天堂在线观看| 欧美激情 亚洲色图| 夜草网站| 静品嫩模一区二区| 91+欧美| 97视频播放| 眼镜人妻101.com| 五月天婷婷色| 男人把坤坤插入女人的下体 | jizzjizz欧美| 91色综合激情| 97色欧洲| 99久久久无码国产精品性啊聊| 91成人久久| 天天透伊人| 婷婷人妻激情| 久久国产性爱| 丝袜综合| 亚洲精品九九九| 精品日韩人妻视频| 97精品国产97久久久久久| 欧美黑人极品高潮喷吹熟女黑人性暴力日韩在线欧美极品一区二区老师 | 亚洲射综合网| 精品国产乱码久久久久久蜜臀| 伊人黄色视频免费观看| 91色图片| 青草精品视频-日本久久久久网站| 欧美日韩不卡a片| 97超碰国产精品| 久久啊啊| 丁香婷婷久久 | 亚洲精品免费中文字幕| 天美国产精品| 91在线观看,天天综合| 无色无码| 亚洲色图 综合| 色伊人91| 中文字幕乱偷人妻久久艾草网| 黄色人人| 男女91| 大肥女高潮bbwbbwhd视频| 色五月婷婷五月天| 国产91美女视频| 亚洲操操操| 日产精品久久久一区二区| av国产无码| 啊啊啊啊啊舒服| 国产日本久久免费精品| WWW美腿丝袜香蕉中文| 日日噜噜夜夜狠狠视频无| 亚洲污一污二| 无码最新| 中文字幕日韩情色| 亚洲一区二区性爱电影| 啊啊啊啊嗯嗯在线久久久| 日本三级R| 国产视频小说| 色噜噜精品一区二区三| 日本黄页视频在线观看| 久久久夜夜嗨免费视频| 日日嗷| 五月天激情小说| 欧美狠狠| 国产精品视频在线播放 | 蜜臀久久99精品久久久久久久久| 欧美翘臀视频网站一区二区三区| 亚洲人人操| 亚洲成人激情小说视频| 麻豆久久久久久久久丝袜| 久久透逼视频| 999熟女精品| 天天插天天射| 国产又黄又粗又猛大片| 狠操91,com| 中文字幕成人| 免费av高清无码| 蜜臀久久99'精品久久久| 五月婷在线| 日本影视久久免费| 夜夜免费视频| www.婷婷六月天| 久久久久久久| 欧美亚洲高清不卡| 97人人射| 日逼视频日本| 性欧美999| 久久99手机免费视频| 国产一区二区a毛片| 五月天伊人网| surenchaopeng| 丁香五月大香蕉| 伊人网免费视频| 香蕉国产97| 嫩草 人人网精品| 婷婷综合五月| 亚洲乱色熟女一区| 99热精品在线观看| 久久妇| 欧美日韩高潮喷水91| 亚洲最大成人a毛毛片| 精品国产乱码久久久久久久久久毛片| 97久久精品国产| 99熟女| 欧美人妻一区| 男女一进一出视频久久| 久久久精选| 色网在线| 久久久com| 久久久精品视频免费观看| 欧美牲| 久久一二三四五六七八九区| 国产精品一区二区三区,亚洲综合| 一级免费啪啪片| 亚洲综合99999| 日韩高潮一区| 大香蕉一区二区在线观看.| 人妻少妇无码| 粉嫩AV一区夜夜嗨| 口爆综合网| 中文字幕在线日亚洲9| 久久黄片国产一区二区| 91美女小视频| 另类欧美| 色一区二区三区综合| 久久精品一区| 久草资源在线视频官方总站日韩丝袜美腿 | 探花精品视频| 操逼逼中文字幕| 免费成人在线观看91| 国产区在线| 伊人欧美大香蕉视频| 欧美日韩少妇色情| 91人妻Pr| 亚洲色婷婷| 国产精品久久伊人| 五月丁香激情综合| 欧美,日韩,亚洲视频| 国产日韩在线播放| 萌白酱自拍视频| 亚洲第一黄色av网站 | 九九热精彩视频| 成人热久久精品| 亚洲一二三| 人人澡综合涩| 极品AV网站在线观看| 91久久久视| 欧洲与亚洲欧美精品中文字幕| 久久伊人在线五区| 国精综合一二三区影视| 黄色高清久久无码依人| 女人的天堂大香蕉网| 老熟妇综合| 色欧洲97| 国产吹潮女在线观看| 成人草草视频| 亚洲黄色电影| 少妇被c 黄 免费观看| 超碰色综合| 51国产午夜精品视频| 欧美操人视频| 中日韩熟女| 日本午夜福利影院| 亚洲情色婷婷五月天| 亚洲国产精品久久久久婷婷青年| 欧美亚洲影视| 久久精品国产精品| 91丝袜人妻| 91丝袜| 国产精品永久免费10000| 蜜臀AV秘一区翔田千里| 国产精品探花在线| 久久久精品成人国产| 人人喜人人妻| 麻豆一区在线| 啊啊啊啊无码| 精品人妻一区二区三区日产乱码| 手机在线播放国产福利| 激情视屏国产乱伦强奸| 毛片中心9视频99| 午夜精品久久久久久久99热影院| 99精品无码| 天天影视亚洲| 肉嘟嘟www视频在线观看高清| 国产精品老师| 99抽插| 国产91丝袜 在线播放| 亚欧毛片基地国产毛片基地| 日本女优在线视频福利| 麻豆天美久久91| 91天美传媒在线观看| 人妻一区二区三区熟女| 亚洲 欧美 制服 另类 自拍| 色婷婷五月综合| 久久夜色一区二区| 中文字幕av片| 亚洲一区二区三区中文字幕| 五月丁香成人网| julia中文字幕在线观看| 日韩精品午夜操呦呦不卡影院| 家庭乱伦国产| 99热| 日本一二三免费久久| 亚洲在线a| 综合一区中亚洲国产成人综合精品 | 天天做天天爱| 国内自拍 日韩激情 99| 欧美久久婷婷| 91在线免费精品视频| 簧片免费看视频| 精品视频久久区| 亚洲āv网址在线观看| 日韩三级一区| 色噜噜狠狠色综无码久久| 18禁免费视频| 狠狠色婷婷| 精品无av| 婷婷久久大香蕉| 97伪v| 国产对白刺激视频| 亚洲 中文 女同| 亚洲国产精品无石码久久| 中文字幕aⅴ在线视频| 密臀视频一区二区三区| 百度百度日本操逼| 97精品一二区| 久久综合97| 五月天激情网图片| 1204人成网站色www| 亚洲强奸乱伦影视网| 四虎国产成人精品免费一女五男| 一级做受视频免费是看美女| www.色婷婷| 日韩91网| 国产精品免费日韩| 久久久久密| 久久精品一区二区三区四区五区| 26uuu欧美| 超碰97男女| 一区二区三区在线资源| 欧美同性恋 的搜索结果 - 91n| 五月天婷精品激情| 91国产丝袜美女| av在线免费一区二区| 久草新免费| 日本操逼视频不卡直接放| 中文字幕乱码人妻一区二区三区,99精品| 97在线视频免费看| 67914亚洲精品| 97免费在线观看视频| 美女人妻色网站| 亚洲国产精品无码AV久久| 国语人妻精彩刺激| 一区二区三区一亚洲中文字幕、综合区灬 | 亚洲本色精品一区二区久久| 天天操天天射青青草| 欧美性爱18观看| 欧洲与亚洲欧美精品中文字幕| 亚洲精品毛片在线观看| 久久99999| a级理论午夜日本| 亚洲人妻色图| 一区二区三区四区五区高清无码永久视频 | 九九干| 日韩淫色网| 国产女同视频在线播放| 欧美91精彩| 国产精品日韩在线一区| AV中文字幕剧情1区2区3| aaaa少妇高潮大片| 综合色好色| 亚洲天堂自拍| 一级性爱aaaa| 97超碰香蕉| 超碰在线97国产| 国产av强奸美女| 亚洲男人在线观看天堂| 日韩激情视频| 蜜乳AV网址| 免费AV中文网在线观看| 色情亚洲日本成人| 五月激情视频| 性色AV蜜色av色欲av| 五月天人妻综合| 亚洲 图片 综合91| 5278欧美一区二区三区| 欧美日韩国产成人高清| 91N综合网在线| 澳门人妻久久| 日本一本道A级黄色毛片试看60分钟| 91网站18禁| 神马久久网| 熟女丰满人妻一区| 91大神精品长腿在线观看网站| av2014 日韩在线中文字幕| 亚洲乱熟女一区二区| 久久久九97| 久干9操| 欧综合网| 久热99999| 亚洲夜色在线| 国产欧美一区激情交| 370p日韩欧美亚洲精品| 这里只有精品97| 久草久日| 在线观看A啊啊啊| 97精彩视频网站| 激情干在线| 熟女五十路一区二区三| 日本伦乱九九九综合| 熟妇高潮二区三区| 天堂伊人久久| 伊色综合天堂色97| 婷婷丁香六月天| 欧美一级久久久久久久大片动画| 麻豆国产97在线| 欧美少妇色图| 蜜区区视频79| 欧美精品不卡一二三四在线91| 天天弄欧美| 成人熟女视频一区二区三区| 亚洲国产激情国产av| 亚洲欧美国产成人综合不卡| www.99中文字幕| 台湾一区国产高清在线| 十八禁啪啪视频| 综合亚洲欧美| 91性感在线| 女人天堂网| 日韩BBN| 久久亚洲欧美一区二区三区-亚洲国产精品第一区二区 | 色制服丝袜夫妻av一区| 久久伊人在线五区| 大香蕉十区| 国产日韩精品一区二区三区| 麻豆区99999| 国模精品一区二区三区苹果色戒 | 四虎视频在线观看| 另类av天堂| 四季AV综合网址| 欧美一区二区成人一卡| 日本顶级天天操狠狠操夜夜操中文字幕 | 婷婷久草一区二区三区| 插穴性爱视频在线观看| 午夜福利无毒不卡| 欧美另类精品xxxx| 精品高清一区二区三区三州| 国产AV久久野战精品| 强奸乱伦大香蕉网| 国产精品免费视频人成| 亚洲精品视频在线播放| 四虎影院成年人片| 校园春色制服丝袜中文字亚洲| 色成人Www精品永久观看| 色综合久| 欧美 亚洲 制服 精品| 日本三级久| 天美一二三在线观看Av| 久久少妇视频| 日本久久久精品电影| 欧美色网络| 精品人妻一区二区三区在| 无码高清少妇久久| 草草影院最新网址| 国模精品娜娜一二三区 | 97人妻人人躁人人玩人人| 欧美色图欧美| 国产91 丝袜在线播放00-百度| 91精品人| 岛国视频免费在线观看| 精品一区二区成人动漫| 久久久久性熟视频| 久久欧洲| 香蕉精品二区二区| 日韩福利综合一区| 乱伦3P视频| 亚洲一区中文字幕久久,果冻传媒一区二区天美传媒| 啊啊啊不要好疼视频| 99在线视频播放| 快灬快灬 一下爽蜜桃在线观看| 91视频综合网| 伊人久操| 日本91白丝| 免费草草草草草视频| 丰满人妻一区二区三区| AV一区观看| 精品久久久无码| 91视频国品一二三区| 五月开心久久AV官网| 国产精品扒开腿做爽爽爽视频| 国产极品粉嫩馒头一线天av| 久久久夜夜嗨免费视频| 久久精品人体| 久久高清无码夜夜操| 26uuu最新| 日本熟妇人妻中出视频| 色狠人在线99| 国产AV中文| 黄在线| 伊人操操| 日少妇视频| 国产亚洲综合欧美一区| 97精品第3页| 伊人超碰97| 欧美成va视频网站| 操91| 日韩操啪| 大香蕉碰碰| 日本不卡二三区| 天天日天天操天天射河南省| 丁香五月激情婷婷| 久草在| 两女互慰AV高潮喷水在线观看| 色蜜AV| 日本精品一区二区三| 做爱A级亚欧| 亚洲情色1区| 超碰色综合| 91爽啪| 精品二区久久| 久久99午夜精品一区人妻| 亚洲激情色片| 国产高清成人免费视频| 国产成人亚洲精品自产在线| 色在线69堂| 收看日本人日bb| 禁十八久久| 欧美色网| 国产a级精品| 超碰97人妻免费在线| 麻豆精品久久久久久久| 亚洲熟妇A V黑人| 91校园春色长篇| avav青青草久久夜| 国产激情综合| 国产白丝AV| 日韩婷婷| 诱惑网综合| 性爱乱伦网址| 热G综合热G中文| 亚洲色综合| 不卡六六在线91| 色欲久久综合| 久草资源在线| 五月丁香亭亭| 久久大黄片| 国产农村妇女精品1区二区| 欧美97| 久久久国产精品人妻丝袜| 天天色天天干天天爱| 加勒比综合九九99视频在线播放| 亚洲国产一区二区入口| 久久一区,青青青青草视频在线播放| 亚洲欧美另类图片| 青青草久久一区网| 91一区二区三区蜜桃| 国产白丝在线| 97香蕉碰碰人妻国产欧美| 亚洲人妻久久久| 天天综合91在线| 一级做a爰片性色毛片久久| 日本九九久久99播| 人人看欧美性爱| 亚洲色婷婷综合久久一区二区三区| 操美女高潮抽搐白浆| 神马久久久久久| 亚洲AV不卡在线观看尤物| 911av网站免费观看| 99这里只有精品| 国产伦精品免编号公布| 天天干天天舔| 久久一二三四五六七八九区| 婷婷色一区| 国产一区二区免费福利片| 一本色道久久综合熟妇| 色欧美天天| 欧美日韩大香蕉| 91天天综合在线观看| 国产欧美一区二区| 99国产精品视频尤物| juliaann丝袜| 亚州日韩97| 操人91| 影音先锋少妇| 中国91AV| 人妻在线中出视频| 秋霞视频一区二区| 欧美一级美片在线观看免费| 老女人91| 欧美日韩黄色片一区二区三区四区人与兽做爱 | 99九九精品| 中文字幕五月婷婷免费| 超碰在线综合97| 新97国产超碰| 丝袜六区| 熟女精品va中文字幕| 国产偷人伦激情在线观看| 玖色av| 青娱乐蜜桃臀AV色婷| 91亚洲人电影| 亚洲精品三| 黑人精品欧美一区二区蜜桃| 影音先锋一区二区在线资源| 男人的天堂亚洲| 懂色av一区二区三区天美传媒| 加勒比av网| 欧美日韩青操| 亚洲综合在线高清| 日本网色| 强奸乱伦αv片| 亚洲小电影免费涩涩成人在线高清 | 超碰在线综合97| 日日夜夜国产综合| 九九天堂| 久久极品伊人| 熟女视频久久| 天天干干天天干干| 日韩熟女操逼| 操一操摸一摸| 亚洲骚逼少妇| 超碰97人人乐| 女人天堂网| 久久精品夜色国产亚洲AV| 少妇人妻精品| 天天日日本| 婷婷香蕉欧美在线一区二区三区| 91性高潮久久久久久久久| 日韩精品视频在线观看一卡二卡| 国产亚洲精品农村妇女| 日本爽爽爽爽爽爽免费视频| 亚州高清av| 亚洲本色精品一区二区久久| 91美| 亚洲丝袜少妇在线| 蜜桃午夜视频一区二区| 超碰精品人妻狠狠干| 蜜桃狠狠色伊人亚洲综合| 97国产天堂岛| 欧美色图 人妻| 国产成人精品午夜福利| 日韩成人色图| 中文字幕精品丝袜| 欧美精品第四五页中文字幕在线观看| 男人的天堂,欧美亚洲另类国产日韩,日本高清一区二区 | 91色碰| 人妻在线臀日韩| 亚洲色图加勒比| 日韩欧美成人大香蕉| 欧美大香蕉97| 欧美 亚洲 另类 综合| 91美女在线视频| 麻豆一区二区三区精品| 超碰97欧美日韩|