# 某大型项目应用本Redis类源码示例(含事务 乐观锁)
### 服务层源码
~~~
/**
* @description
* @author Mikkle
*/
public function completeParkByBill($data){
$this->functionName = __FUNCTION__;
$this->args = $data;
//检验数据
if ( ! isset($data[OptionsCenter::$fieldChargeToken]) || ! $this->parseToken($data[OptionsCenter::$fieldChargeToken]) ){
$this->addError("登录Token参数缺失或已经失效");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
if(! $this->checkArrayValueEmpty($data,[OptionsCenter::$fieldBillNum,OptionsCenter::$fieldPayMoney])){
$this->addError("信息中缺失必要的信息");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
$billCenter = BillInfoCenter::instance($data[OptionsCenter::$fieldBillNum]);
$data[OptionsCenter::$fieldSerialNum] = $billCenter->getParkCarSerialNum();
$data[OptionsCenter::$fieldParkMoney] = $billCenter->getInfoFieldValue(OptionsCenter::$fieldParkMoney);
$data[OptionsCenter::$fieldBillMoney] = $billCenter->getInfoFieldValue(OptionsCenter::$fieldBillMoney);
if (!is_numeric($data[OptionsCenter::$fieldBillMoney])|| !is_numeric($data[OptionsCenter::$fieldPayMoney]) ){
$this->addError("账单金额类型错误");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}elseif ( $data[OptionsCenter::$fieldPayMoney]<=0){
$this->addError("付款金额不能小于等于0");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}elseif ($data[OptionsCenter::$fieldBillMoney] != $data[OptionsCenter::$fieldPayMoney]){
if ($data[OptionsCenter::$fieldBillMoney]> $data[OptionsCenter::$fieldPayMoney]){
if (!$this->checkArrayValueEmpty($data,[ OptionsCenter::$fieldDebtType]) || $data[ OptionsCenter::$fieldDebtType] !=2 ){
$this->addError("付款金额小于订单金额时,缺失拒付类型正确参数");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
}elseif ($data[OptionsCenter::$fieldBillMoney] < $data[OptionsCenter::$fieldPayMoney]){
$this->addError("付款金额不可以大于订单金额");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
}
//流水号信息验证
if ( ! isset($data[OptionsCenter::$fieldSerialNum]) || empty($data[OptionsCenter::$fieldSerialNum]) ){
$this->addError("信息中缺失必要的停车序号信息");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
if (!AuthCenter::existParkSerialBySerialId($data[OptionsCenter::$fieldSerialNum])){
$this->addError("信息中的序号信息不正确");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
};
$carSerialCenter = CarSerialCenter::instance($data[OptionsCenter::$fieldSerialNum]);
$parkingInfo = $carSerialCenter->getParkingInfo($this->options);
if ($parkingInfo[OptionsCenter::$fieldBillNum] != $data[OptionsCenter::$fieldBillNum]){
$this->addError("你的Bill单号已经过期,请使用最新的Bill号");
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
//检测流水订单状态
if (!$this->checkParkSerialBillState($parkingInfo)){
return ShowCode::jsonCodeWithoutData(1003,$this->error);
}
//判断账单是否有5分钟内的结清账单
if ($this->checkBillPayState($parkingInfo)){
return ShowCode::jsonCode(1099,[OptionsCenter::$fieldSerialNum=>$data[OptionsCenter::$fieldSerialNum]]);
}
$endTime = $billCenter->getInfoFieldValue(OptionsCenter::$fieldEndTime);
//附加上收费员信息和日报ID
$data[OptionsCenter::$idCharge] = $this->chargeId;
$data[OptionsCenter::$idDocument] = $this->terminalId;
if ($data[OptionsCenter::$fieldBillMoney] == $data[OptionsCenter::$fieldPayMoney] ){
$status = 2;
}elseif($data[OptionsCenter::$fieldBillMoney] > $data[OptionsCenter::$fieldPayMoney]){
$status = 1;
}else{
$status = 0;
}
//获取已经付款金额
$alreadyPayMoney = $this->getAlreadyPayMoney($parkingInfo);
if ($alreadyPayMoney>0){
}
$billData =[
OptionsCenter::$fieldBillNum=>$data[OptionsCenter::$fieldBillNum],
OptionsCenter::$fieldPayMoney => $data[OptionsCenter::$fieldPayMoney],
OptionsCenter::$fieldBillTime =>$this->getTime($endTime),
OptionsCenter::$fieldBillStatus =>$status ,
];
$serialData= [
OptionsCenter::$prefixEnd . OptionsCenter::$idCharge => $this->chargeId,
OptionsCenter::$prefixEnd . OptionsCenter::$nameCharge => $this->chargeName,
OptionsCenter::$prefixEnd . OptionsCenter::$idTerminal => $this->terminalId,
OptionsCenter::$fieldParkMoney => $data[OptionsCenter::$fieldParkMoney] ,
//总付款金额
OptionsCenter::$fieldPayMoney => $alreadyPayMoney+$data[OptionsCenter::$fieldPayMoney],
OptionsCenter::$fieldPayStatus => $status , //已结清费用2 部分为1
OptionsCenter::$fieldEndTime => $this->getTime($endTime),
OptionsCenter::$fieldCompleteTime => time(),
OptionsCenter::$stringStatus => 2,
];
switch (true){
//全款结账账单
case($status==2):
if ( !$carSerialCenter->completeBillSerialByAllCash($data,$serialData,$billData)){
return ShowCode::jsonCode(1008,"存储停车信息失败");
}
//处理报表信息
DocumentInfoCenter::instance($this->documentId)->updateDocumentByParkSerialNum($data[OptionsCenter::$fieldSerialNum]);
//清除泊位信息
if ($this->checkArrayValueEmpty($parkingInfo,OptionsCenter::$idPlace)){
$this->clearPlaceParkInfo($parkingInfo[OptionsCenter::$idPlace],$data[OptionsCenter::$fieldSerialNum]);
}
return ShowCode::jsonCode(1001, $carSerialCenter->getParkingInfo(),"",[OptionsCenter::$stringVersion=>ParkInfoCenter::instance($this->parkId)->updateVersion()]);
break;
//拒付部分订单
case($status==1):
if ( !$carSerialCenter->completeBillSerialByPartCash($data,$serialData,$billData)){
return ShowCode::jsonCode(1008,"存储停车信息失败");
}
//处理报表信息
DocumentInfoCenter::instance($this->documentId)->updateDocumentByParkSerialNum($data[OptionsCenter::$fieldSerialNum]);
//清除泊位信息
if ($this->checkArrayValueEmpty($parkingInfo,OptionsCenter::$idPlace)){
$this->clearPlaceParkInfo($parkingInfo[OptionsCenter::$idPlace],$data[OptionsCenter::$fieldSerialNum]);
}
return ShowCode::jsonCode(1001, $carSerialCenter->getParkingInfo(),"",[OptionsCenter::$stringVersion=>ParkInfoCenter::instance($this->parkId)->updateVersion()]);
break;
}
return ShowCode::jsonCode(1008,"你不应该看到这个");
}
~~~
### 数据逻辑处理
~~~
/**
* @description
* @author Mikkle
*/
public function completeBillSerialByPartCash($data, $serialData, $billData){
//获取当前的收费员的帐号余额和版本号
$chargeAmount = Db::table(OptionsCenter::$tableCharge)
->where([OptionsCenter::$pk =>$data[OptionsCenter::$idCharge]])
->field([OptionsCenter::$stringAmount,OptionsCenter::$prefixAmount.OptionsCenter::$stringVersion])->find();
if (!is_numeric($chargeAmount[OptionsCenter::$stringAmount]) || !is_numeric($chargeAmount[OptionsCenter::$prefixAmount.OptionsCenter::$stringVersion]) ){
throw new Exception("收费员的余款数据不正确");
}
$amount = (int)$chargeAmount[OptionsCenter::$stringAmount];
$newAmount = $amount-(int)$data[OptionsCenter::$fieldPayMoney];
$version = (int)$chargeAmount[OptionsCenter::$prefixAmount.OptionsCenter::$stringVersion];
//收费员账户流水表信息
$chargePriceDate = [
OptionsCenter::$fieldBillNum=>$data[OptionsCenter::$fieldBillNum],
OptionsCenter::$stringType=>2, //金额的类型 (1为 充值 2为扣除)
OptionsCenter::$stringMode=>2 , //充值方式(1 人工充值或扣除) 2 现金缴款扣除
OptionsCenter::$stringDesc=>"停车单:{$data[OptionsCenter::$fieldBillNum]}扣款",
OptionsCenter::$stringPrice => $data[OptionsCenter::$fieldPayMoney],
OptionsCenter::$stringAmount => $newAmount,
];
$serialInfo = $this->getInfoList();
//设置拒付信息
$debtData=[
OptionsCenter::$fieldDebtNum=>RandNumCenter::createDebtSerialNumber(), //欠费流水号
OptionsCenter::$fieldSerialNum=> $serialInfo[OptionsCenter::$fieldSerialNum], //停车流水号
OptionsCenter::$fieldCarCode=>$serialInfo[OptionsCenter::$fieldCarCode],
OptionsCenter::$idPark=>$serialInfo[OptionsCenter::$idPark],
OptionsCenter::$namePark=>$serialInfo[OptionsCenter::$namePark],
OptionsCenter::$fieldDebtType=>2, //拒缴部分
OptionsCenter::$fieldStartTime=>$serialInfo[OptionsCenter::$fieldStartTime],
OptionsCenter::$prefixStart.OptionsCenter::$idCharge=>$serialInfo[OptionsCenter::$prefixStart.OptionsCenter::$idCharge],
OptionsCenter::$prefixStart.OptionsCenter::$nameCharge=>$serialInfo[OptionsCenter::$prefixStart.OptionsCenter::$nameCharge],
OptionsCenter::$fieldEndTime=>$serialData[OptionsCenter::$fieldEndTime],
OptionsCenter::$prefixEnd.OptionsCenter::$idCharge => $serialData[OptionsCenter::$prefixEnd.OptionsCenter::$idCharge],
OptionsCenter::$prefixEnd.OptionsCenter::$nameCharge => $serialData[OptionsCenter::$prefixEnd.OptionsCenter::$nameCharge],
OptionsCenter::$stringStatus=>1,
OptionsCenter::$fieldCreateTime=>time(),
OptionsCenter::$fieldParkMoney=>$serialData[OptionsCenter::$fieldParkMoney],
OptionsCenter::$fieldPayMoney=>$serialData[OptionsCenter::$fieldPayMoney],
OptionsCenter::$fieldDebtMoney => (int)($serialData[OptionsCenter::$fieldParkMoney] - $serialData[OptionsCenter::$fieldPayMoney]) ,
];
//设置付款信息
$payDate=[
OptionsCenter::$fieldPayNum=>RandNumCenter::createPaySerialNumber(),
OptionsCenter::$fieldBillNum=>$data[OptionsCenter::$fieldBillNum],
OptionsCenter::$fieldSerialNum=>$this->infoId,
OptionsCenter::$idPark=>$serialData[OptionsCenter::$idPark],
OptionsCenter::$fieldPayType=>1,
OptionsCenter::$fieldPayMoney=>$data[OptionsCenter::$fieldPayMoney],
OptionsCenter::$fieldPayTime=>RandNumCenter::getTimeString(),
OptionsCenter::$fieldCreateTime=>time(),
OptionsCenter::$stringStatus=>1,
];
try{
//多表处理 开启事务
Db::startTrans();
//升级收费员余额 加入了乐观锁判断
if (!Db::table(OptionsCenter::$tableCharge)
->where([OptionsCenter::$pk=>$data[OptionsCenter::$idCharge],OptionsCenter::$prefixAmount.OptionsCenter::$stringVersion =>$version ])
->update([OptionsCenter::$stringAmount=>$newAmount,OptionsCenter::$prefixAmount.OptionsCenter::$stringVersion=>$version+1])
){
throw new Exception("操作员的余额信息已经变动,请重试");
}
//插入欠费信息
if (!Db::table(OptionsCenter::$tableParkInfoDebt)->insert($debtData)){
throw new Exception("插入欠费信息失败");
}
//插入付款流水信息
if (!Db::table(OptionsCenter::$tableParkInfoPay)->insert($payDate)){
throw new Exception("插入付款流水信息失败");
}
//插入金额流水信息
if (!Db::table(OptionsCenter::$tableChargePrice)->insert($chargePriceDate)){
throw new Exception("插入金额流水信息失败");
}
if (!Db::table(OptionsCenter::$tableParkInfoTemp)->where([OptionsCenter::$fieldSerialNum=>$this->infoId])->update($serialData)){
throw new Exception("保存订单流水信息失败");
}
if (!Db::table(OptionsCenter::$tableParkInfoBill)->where([OptionsCenter::$fieldBillNum=>$data[OptionsCenter::$fieldBillNum]])->update($billData)){
throw new Exception("完成账单信息失败");
}
$this->updateAllBillBySerialNumToComplete();
//更新流水信息
$this->setInfoArray($serialData);
//更新账单信息
BillInfoCenter::instance($data[OptionsCenter::$fieldBillNum])->setInfoArray($billData);
//设置7天 自动释放redis内存
BillInfoCenter::instance($data[OptionsCenter::$fieldBillNum])->setExpire(3600*24*7);
//更新帐号余额
ChargeInfoCenter::instance($data[OptionsCenter::$idCharge])->refreshChargeAmount($newAmount);
//处理泊位信息
$this->setExpire(3600*24*7);
Db::commit();
return true;
}catch (Exception $e){
Log::error($e->getMessage());
dump($e);
Db::rollback();
return false;
}
}
~~~
感谢大家关注 交流请加QQ群 321449759
![](https://box.kancloud.cn/3499008a08e64306c68873288092a057_286x340.png)
- 序言及更新日志
- 前言一 开发PHP必备的环境(你可以不看)
- LinUX系统ThinkPHP5链接MsSQL数据库的pdo_dblib扩展
- centos7.2挂载硬盘攻略
- Centos系统Redis安装及Redis的PHP扩展安装
- Centos系统增加Swap(系统交换区)的方法
- 前言二 开发PHP软件配置和介绍(你依然可以不看)
- 数据库SQL文件
- 本地Git(版本控制)的搭建
- GIT远程仓库的克隆和推送
- Git常用命令
- PHP面向对象思想实战经验领悟
- PHP面向对象实战----命名空间
- PHP面向对象实战----继承
- 基类实战--底层方法封装
- 基类实战--构造函数实战
- 基类实战--析构函数的使用
- TP5实战开发前篇---控制器(controller)
- 控制器中Request类的使用
- 控制器中基类的使用
- TP5实战开发前篇---模型篇(model)
- TP5实战开发前篇---验证器篇(Validate)
- TP5实战课程入门篇---花拳绣腿
- 模块以及类的文件的建立
- Api开发------单条信息显示
- Api开发---单条信息复杂关联显示
- Api开发---查询信息缓存Cache的应用
- TP5实战技巧---开发思路 引路造桥
- TP5实战技巧---整合基类 化繁为简
- TP5实战课程入门篇---数据操作
- Api开发---数据的添加和修改
- API开发---快速开发API通用接口
- TP5专用微信sdk使用教程
- THINKPHP5微信SDK更新记录及升级指导
- TP5专用SDK 微信参数配置方法
- 微信公众号推送接口对接教程
- 微信推送接口对接示例含扫描登录微信端部分
- TP5专用微信支付SDK使用简介
- TP5专用支付宝支付SDK使用说明
- 使用NW将开发的网站打包成桌面应用
- TP5高阶实战课程 进阶篇概述
- 进阶篇一 实战开发之习惯及要求
- 进阶篇二 实战开发之控制器
- 控制器基类之控制器基类使用方法
- 控制器基类之控制器基类常用方法分享
- 控制器基类之构造函数的使用方法
- 进阶篇三 实战开发之权限控制
- TP5实战源码 --- 全局用户信息验证类Auth
- TP5实战源码 --- 微信Auth实战开发源码
- 进阶篇四 实战开发之模型
- 模型基类之模型基类的用途
- 模型基类之常用数据处理方法
- 模型逻辑层之实战代码(含事务)
- 模型实战开发之模型常用方法
- 模型实战源码 --- 乐观锁的应用
- 模型实战技巧---Model事件功能的使用
- 模型事件实战应用---数据库操作日志
- 进阶篇五 实战开发之缓存(Cache)
- TP5实战源码---应用缓存获取城市信息
- TP5实战源码---应用缓存获取分类详情
- 进阶篇六 TP5类库的封装和使用
- DataEdit快捷操作类库
- ShowCode快捷使用类库
- 阿里大于 短信API接口 TP5专用类库
- DatabaseUpgrade数据库对比及更新类库
- AuthWeb权限类使用说明
- 进阶篇七 服务层的应用
- 服务层源码示例
- 服务层基类源码
- 进阶篇八 应用层Redis数据处理基类
- Redis服务层基类源码
- 进阶篇九 使用Redis类库处理一般的抢购(秒杀)活动示例
- 进阶篇十 某大型项目应用本Redis类源码示例(含事务 乐观锁)
- 进阶篇十一 逻辑层的应用
- 逻辑层基类源码
- 进阶篇 服务层代码示例
- 高阶实战课程 进阶篇持续新增中
- 高阶篇一 TP5命令行之守护任务源码
- TP5实战源码 --- 命令行
- TP5实战源码 --- 通过shell建立PHP守护程序
- 高阶篇二 使用Redis队列发送微信模版消息
- 高阶篇二 之 Worker队列基类源码
- 高阶篇三 TP5实战之Redis缓存应用
- Redis实战源码之Hash专用类库源码
- Redis实战源码之Model类结合
- Redis实战源码之模型Hash基类源码
- Redis实战源码之Hash查询使用技巧
- Redis实战源码之 shell脚本中redis赋值和取值
- 高阶篇四 Swoole的实战应用
- swoole基类代码
- Swoole扩展WebsocketServer专用类
- 基于Swoole的多Room聊天室的程序
- Swoole守护服务shell源码
- 高阶篇五 命令行异步多进程队列类的应用
- tp_worker类源码
- WorkerBase
- WorkerCommand
- WorkerRedis
- Redis类
- CycleWorkBase
- WorkerHookBase异步钩子
- 队列日志SQL
- 高阶篇六 定时执行队列类库以及使用方法
- 定时队列类库源码
- 高阶篇七 异步执行循环队列类库以及使用教程
- CycleWorkBase源码
- 高阶实战课程 进阶篇持续新增中
- Extend便捷类库源码库
- 阿里相关类库
- SendSms--验证码API接口文件
- 权限相关类库目录
- AuthWeb 权限验证类库
- Redis便捷操作类库(20171224更新)
- Redis
- Tools工具类库集
- Curl类库
- DataEdit
- Rand类库
- ShowCode类库
- Upload类库
- 附件集合
- 附件一:微信支付 实战开发源码
- 微信支付类库源代码
- Common_util_pub.php
- DownloadBill_pub.php
- JsApi_pub.php
- NativeCall_pub.php
- NativeLink_pub.php
- OrderQuery_pub.php
- Refund_pub.php
- RefundQuery_pub.php
- SDKRuntimeException.php
- ShortUrl_pub.php
- UnifiedOrder_pub.php
- Wxpay_client_pub.php
- Wxpay_server_pub.php
- WxPayConf_pub.php
- 微信支付回调页面源码
- 附件二 顺丰快递BSP接口实战开发源码
- 顺丰快递BSP接口实战开发源码
- 顺丰BSP基类
- 顺丰BSP基础代码
- 顺丰BSP下单接口
- 顺丰BSP查单接口
- 顺丰BSP确认/取消接口
- 附件三 APP注册登陆接口源码(含融云平台接口)
- 附件四 TP5订单Model(含事务 获取器 修改器等方法)
- 附录五 RSA加密解密
- Rsa文件源码
- 附件六 阿里大于短信接口
- 附件七 AES加解密类
- AES加解密类源码
- 附件八 TP5路由设置源码
- 附件九 TP5 Excel导入导出下载便捷类库
- Excel类库TP5源码
- 附件十 TP5便捷操作Redis类库源码
- TP5源码 Redis操作便捷类库
- 附件十一 TP5源码 上传文件入库类源码
- 上传类Upload源码
- Upload类上传配置文件
- 存储图像文件的数据库SQL文件
- 存储文件的数据库SQL文件
- 附件十二 TP5 图片处理增强类 支持缩略图在线显示
- 附件十三 微信推送消息接口类库源码
- 附件十三 微信推送消息接口类库源码 之 基类
- 附件十四 存储微信昵称的处理方法