EF+SQLSERVER 제어 및 보너스 뺏기 잔액 감소(개선)
어떻게 같은 시간에 데이터베이스에서 보너스 잔액을 삭감하는 것이 틀리지 않도록 제어합니까?이전에 우리의 방법은 프로그램을 직접 잠그는 것이다. 이렇게 하면 가져오는 나쁜 점은 대기 시간이 너무 길고 한 라인이 들어갈 때마다 다음과 같은 몇 가지 과정을 거쳐야 한다는 것이다.
과정은 각각
1. 시계 찾기
2. 정보 검증
3. 위챗 서버 보내기
4. 피드백 대기
5. 업데이트 테이블
이 과정들이 끝난 후에야 다음 과정으로 돌아간다.꽃이 다 질 때까지 기다려야지~
또한 위챗 서버를 보내는 과정은 0s에서 9s까지 시간이 다르다.많은 여유 시간이 생기고, 이곳의 CPU는 대량의 여유를 발생시킨다.그리고 이런 상황도 부하 균형을 계속할 수 없기 때문에 여러 사이트의 배치가 있으면 반드시 데이터베이스 병발 문제가 발생할 것이다.
만약 시계를 검사하기 전에 자물쇠를 채워 업데이트한 후에 방출한다면 데이터베이스가 병발되지 않을 것이라고 말하지만.그러나 두 번째 라인이 조회에 들어갈 때 그는 계속 기다렸고, 그 소모 시간은 더 많은 잠금 프로그램과 차이가 없었다.
개량하다
이 아이디어는 분포식 사무의 디자인에서 비롯된 것으로 보너스 잔액을 미리 공제하는 방식으로 위챗 서버의 피드백을 기다리지 않고 다음 라인에서 관련 임무를 계속 수행할 수 있도록 한다.위챗 서버가 피드백을 돌아왔을 때, 비로소 다른 사무를 시작하여 거래 상태를 바꾸기 시작한다.피드백 결과가 FAIL이면 미리 공제된 보너스 잔액을 복원해야 합니다.
실제 환경을 모의하는 테스트 코드를 대충 썼고, 훙바오를 뺏는 동작을 모의했다
private void task()
{
for (int i = 0; i < 50; i++)
{
string tradeNo = Qxun.Framework.Utility.CreateOrderNo.DateTimeAndNumber();
try
{
using (var trans = new TransactionScope())
{
using (var dbContext = new ActivityDbContext())
{
//
var model = dbContext.Database.SqlQuery(@"select * from VIPPassRedBag013 with(updlock) where ActivitySceneID=199").FirstOrDefault();
var mode = dbContext.Database.SqlQuery(@"select * from VIPPassRedBag013Mode with(updlock) where ActivitySceneID=199").ToList();
//
Thread.Sleep(5);
//
VIPPassRedBag013Mode currentMode = null;
foreach (var modeItem in mode)
{
if (modeItem.RemainCount > 0)
{
currentMode = modeItem;
break;
}
}
//
if (currentMode != null && model != null && model.RedBagBalance >= currentMode.Money)
{
VIPPassRedBag013Play currentPlayModel = new VIPPassRedBag013Play();//
currentPlayModel.VIPPassRedBag013ModeID = currentMode.ID;
currentPlayModel.WeixinUserID = Thread.CurrentThread.ManagedThreadId;
currentPlayModel.Money = Convert.ToInt32(currentMode.Money * 100);// ( )
currentPlayModel.TradeNumber = tradeNo;
currentPlayModel.Status = (int)TradeStatus.Trading;
currentPlayModel.VIPPassRedBag013ModeID = currentMode.ID;
currentPlayModel.ActivitySceneID = 199;
dbContext.Insert(currentPlayModel);
currentMode.RemainCount -= 1;
dbContext.Update(currentMode);
model.RedBagBalance -= currentMode.Money;
dbContext.Update(model);
trans.Complete();
}
else
{
trans.Complete();
}
}
}
}
catch (Exception ex){}
//
string returnCode = "SUCCESS";
Random ran = new Random();
int time = ran.Next(100);
if (time <= 1)
{
returnCode = "FAIL";
}
//
Thread.Sleep(time * 100);
//
bool retry = true;
int retryCount = 0;
do
{
Qxun.Activity.Contract.VIPPassRedBag013 model = null;
VIPPassRedBag013Play playModel = null;
VIPPassRedBag013Mode mode = null;
try
{
using (var trans = new TransactionScope())
{
using (var dbContext = new ActivityDbContext())
{
//
model = dbContext.Database.SqlQuery(@"select * from VIPPassRedBag013 with(updlock) where ActivitySceneID=199").FirstOrDefault();
playModel = dbContext.Database.SqlQuery(@"select * from VIPPassRedBag013Play with(updlock) where TradeNumber='" + tradeNo + "'").FirstOrDefault();
mode = dbContext.Database.SqlQuery(@"select * from VIPPassRedBag013Mode with(updlock) where ID=" + playModel.VIPPassRedBag013ModeID).FirstOrDefault();
if (returnCode == "SUCCESS")
{
playModel.Status = (int)TradeStatus.Success;
playModel.Remark = "retry=" + retryCount + ",success;time=" + DateTime.Now.ToString();
playModel.FinishTime = DateTime.Now;
dbContext.Update(playModel);
trans.Complete();
retry = false;
}
else
{
model.RedBagBalance += mode.Money;
dbContext.Update(model);
playModel.Status = (int)TradeStatus.Fail;
playModel.Remark = "retry=" + retryCount + ",fail;time=" + DateTime.Now.ToString();
playModel.FinishTime = DateTime.Now;
dbContext.Update(playModel);
mode.RemainCount += 1;
dbContext.Update(mode);
trans.Complete();
retry = false;
}
}
}
}
catch (Exception ex)
{
//
//
retryCount++;
retry = true;
}
if (retryCount > 5)
{
break;
}
} while (retry);
}
}
100명을 시뮬레이션하여 동시에 훙바오를 뺏다
public ActionResult Excute()
{
for (int i = 0; i < 100; i++)
{
Thread thread = new Thread(new ThreadStart(task));
thread.Start();
}
return Content(" !");
}
위 코드는retry 변수 제어를 사용하여 긴 기다림으로 인한 시간 초과를 방지하여 모든 주문서를 처리할 수 있도록 합니다.그러나 실제 라인 수량이 100-200일 때 10~20개의 VIPpass RedBag013 Play 주문 상태가 Trading으로 유지됩니다.라인 수가 200보다 많을 때 불안정해져 어떤 원인을 찾지 못하고 있다.인연이 있는 사람이 하나 둘 가르쳐 주기를 바란다.
이런 현상을 해결하기 위해 저는 Global에서 10분 전의 VIPpass RedBag013 Play를 주기적으로 찾아갔고 주문 상태가 Trading인 쪽지를 작성했습니다(10분이 지났는데도 아직 처리하지 못했으니 처리하지 못했습니다).주문 번호를 받고 위챗의 훙바오 거래 기록을 다시 찾아라.위챗 훙바오 피드백 결과를 통해 데이터베이스의 거래 상태를 업데이트합니다.
public ActionResult Check()
{
using (var dbContext = new ActivityDbContext())
{
//
var playModel = dbContext.Database
.SqlQuery(@"select * from VIPPassRedBag013Play with(nolock) where ActivitySceneID=199 and[status] = 2 and DATEDIFF(MINUTE, CreateTime, GETDATE()) > 10").ToList();
if (playModel != null && playModel.Count > 0)
{
foreach (var item in playModel)
{
using (var trans = new TransactionScope())
{
//
string returnCode = "SUCCESS";
Random ran = new Random();
int time = ran.Next(100);
if (time <= 1)
{
returnCode = "FAIL";
}
//
//
Thread.Sleep(time * 100);
if (returnCode == "SUCCESS")
{
item.Status = (int)TradeStatus.Success;
item.Remark = "success;time=" + DateTime.Now.ToString();
item.FinishTime = DateTime.Now;
dbContext.Update(item);
trans.Complete();
}
else
{
Qxun.Activity.Contract.VIPPassRedBag013 model = dbContext.Database
.SqlQuery(@"select * from VIPPassRedBag013 with(updlock) where ActivitySceneID=199")
.FirstOrDefault();
VIPPassRedBag013Mode mode = dbContext.Database
.SqlQuery(@"select * from VIPPassRedBag013Mode with(updlock) where ID=" + item.VIPPassRedBag013ModeID).FirstOrDefault();
model.RedBagBalance += item.Money;
dbContext.Update(model);
item.Status = (int)TradeStatus.Fail;
item.Remark = "fail;time=" + DateTime.Now.ToString();
item.FinishTime = DateTime.Now;
dbContext.Update(item);
mode.RemainCount += 1;
dbContext.Update(mode);
trans.Complete();
}
}
}
}
}
return View();
}
PS:이렇게 개선하면 이전보다 훨씬 좋아질 거예요.물론 이러기에는 턱없이 부족하다.여러분이 지나가는 대신이 하나 둘 가르쳐 주시기를 바랍니다. 대단히 감사합니다!
다음으로 전송:https://www.cnblogs.com/chenjianxiang/p/6387784.html
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.