プロモーションバックグラウンド-カスタマーサービスロット発券実現方案
3971 ワード
電子商取引の各業務はすべて人工的に発券する需要があって、客服あるいは運営してCRMの楽屋で直接発券する必要があって、PMは私に大量に発券する需要を投げます.
キーフィールド:ロット番号(BatchId)、カード番号(rpCodesは複数入力、カンマ区切りをサポート)、ユーザーID(userIdsは複数入力、カンマ区切りをサポート、一括アップロードExcelフォーマットをサポート)
フロントエンドはバックグラウンドのロット券インタフェースを呼び出した後、直接クエリーインタフェースに戻り、バックグラウンドのロット券インタフェースはマルチスレッド非同期券を発行する.
発券結果フィールド:ロット番号(BatchId)、カード番号、ロット数(rpCodes*userIds)、成功数、失敗数、リリース時間、ステータス
----------------------------------------------------------------------------------------------------------------------------------------------------------
以上が需要であり、以下に実現案を述べる.
補助券を作るだけで、他の業務ラインの人員が大量に券を出すのを避けるために、このインターフェースを歩いているので、券の総量を検査して、2000枚以上の券の流量をすべて止めます.
1.発行券数量の検証
2.一括発行基本情報を記録し、userIdsフィールドが大きすぎるため、DBAは別のテーブルを保存し、基本情報テーブルのプライマリ・キーで関連付けます.
3.発券
4.操作記録を記録する
第3部発券の実現の細部にはボスの意見と少し違いがある.
userIdsが500未満の場合、5つのスレッドから発券し、マルチスレッドが返す結果をどのように処理するかが重要です.
私の意見は、JavaのFork/Joinフレームワークを使用して、すべてのスレッドの結果をまとめ、一括発券基本情報テーブルを更新しますが、そうすると、スレッドがすべて完了し、データベースが更新されるか、データベースが更新されないか、スレッドが異常であれば、CRMは実際に成功した回数券、失敗した回数券を見ることができません.
Bossの意見では、スレッドごとに戻る場合、直接一括発券基本情報テーブルを更新するには、5回更新する必要があります.MySQLでupdateを行う際に条件が付けられており、条件にインデックスフィールドが含まれているため、MySQLの行ロックを利用して、スレッドが一括発券基本情報テーブルのレコードを同時に更新しても、汚れたデータが書き込まれることはありません.あるスレッドが間違っていても、他のスレッドの戻りには影響しません.
発券部分のコードを添付します.
説明:sendPersonalReward関数は詳細すぎて、敏感なビジネス情報が含まれていて、展示しにくいです.
キーフィールド:ロット番号(BatchId)、カード番号(rpCodesは複数入力、カンマ区切りをサポート)、ユーザーID(userIdsは複数入力、カンマ区切りをサポート、一括アップロードExcelフォーマットをサポート)
フロントエンドはバックグラウンドのロット券インタフェースを呼び出した後、直接クエリーインタフェースに戻り、バックグラウンドのロット券インタフェースはマルチスレッド非同期券を発行する.
発券結果フィールド:ロット番号(BatchId)、カード番号、ロット数(rpCodes*userIds)、成功数、失敗数、リリース時間、ステータス
----------------------------------------------------------------------------------------------------------------------------------------------------------
以上が需要であり、以下に実現案を述べる.
補助券を作るだけで、他の業務ラインの人員が大量に券を出すのを避けるために、このインターフェースを歩いているので、券の総量を検査して、2000枚以上の券の流量をすべて止めます.
1.発行券数量の検証
2.一括発行基本情報を記録し、userIdsフィールドが大きすぎるため、DBAは別のテーブルを保存し、基本情報テーブルのプライマリ・キーで関連付けます.
3.発券
4.操作記録を記録する
第3部発券の実現の細部にはボスの意見と少し違いがある.
userIdsが500未満の場合、5つのスレッドから発券し、マルチスレッドが返す結果をどのように処理するかが重要です.
私の意見は、JavaのFork/Joinフレームワークを使用して、すべてのスレッドの結果をまとめ、一括発券基本情報テーブルを更新しますが、そうすると、スレッドがすべて完了し、データベースが更新されるか、データベースが更新されないか、スレッドが異常であれば、CRMは実際に成功した回数券、失敗した回数券を見ることができません.
Bossの意見では、スレッドごとに戻る場合、直接一括発券基本情報テーブルを更新するには、5回更新する必要があります.MySQLでupdateを行う際に条件が付けられており、条件にインデックスフィールドが含まれているため、MySQLの行ロックを利用して、スレッドが一括発券基本情報テーブルのレコードを同時に更新しても、汚れたデータが書き込まれることはありません.あるスレッドが間違っていても、他のスレッドの戻りには影響しません.
発券部分のコードを添付します.
/**
* , 500 , 5
* @param rpCodes
* @param memberIds
* @param batchId
*/
private void receiveRps(String[] rpCodes, String[] memberIds, String batchId) {
List memberId = Arrays.asList(memberIds);
if(memberIds.length <= 500){
sendCoupons(rpCodes, memberId, batchId);
} else {
List> splitList = splitMemberIds(memberId);
for(List subList : splitList){
sendCoupons(rpCodes, subList, batchId);
}
}
}
/**
*
* @param rpCodes
* @param memberIds
* @param batchId
*/
private void sendCoupons(String[] rpCodes, List memberIds, String batchId){
threadPool.execute(()-> {
try {
LOG.info("****.sendCoupons ,memberIds:{}, rpCodes:{}, batchId:{}", JsonUtil.toString(memberIds), JsonUtil.toString(rpCodes), batchId);
//
int successCount = 0;
int faultCount = 0;
for(String memberId : memberIds){
SendPersonalRewardDto sendPersonalRewardDto = sendPersonalReward(memberId, rpCodes, batchId);
successCount += sendPersonalRewardDto.getSuccessCount();
faultCount += sendPersonalRewardDto.getFaultsCount();
}
// , , MySQL update
synchronized (this){
HashMap param = new HashMap<>();
param.put("batchId",batchId);
param.put("successCount",successCount);
param.put("faultCount",faultCount);
int updateRes = iBatchCouponDao.updateBatchBasicInfoRecord(param);
if(updateRes != 1){
LOG.error("****.sendCoupons , ,memberIds:{}, rpCodes:{}, batchId:{}" , JsonUtil.toString(memberIds), JsonUtil.toString(rpCodes), batchId);
}
}
}catch (Exception e){
LOG.error("****.sendCoupons ,memberIds:{}, rpCodes:{}, batchId:{}", JsonUtil.toString(memberIds), JsonUtil.toString(rpCodes), batchId);
}
});
}
private List> splitMemberIds(List memberId){
List> list = new ArrayList<>();
int avgNumber= memberId.size() / 5;
for(int i = 0; i < 4; i++){
List sublist = memberId.subList(i * avgNumber, i * avgNumber + avgNumber);
list.add(sublist);
}
list.add(memberId.subList(4 * avgNumber, memberId.size()));
return list;
}
説明:sendPersonalReward関数は詳細すぎて、敏感なビジネス情報が含まれていて、展示しにくいです.