PHP 결제 시스템 디자인 과 전형 적 인 사례 공유
이 시스템 은 소형 결제 시스템 으로 도 사용 할 수 있 고 제3자 응용 으로 개방 플랫폼 에 접속 할 때의 결제 흐름 시스템 으로 도 사용 할 수 있다.
원래 의 수요 가 비교적 책임감 이 있 기 때문에 나 는 간단하게 말 했다.
모든 응용 프로그램 에 대해 대외 적 으로 잔액 획득,지불 설비,충전 등 인 터 페 이 스 를 제공 해 야 한다.
백 스테이지 에 절차 가 있어 서 매달 1 일 에 청산 을 한다.
계 정 이 동 결 될 수 있 습 니 다.
매번 작업 의 흐름 을 기록 해 야 하 며,매일 흐 르 는 물 은 발기인 과 장 부 를 대조 해 야 한다.
위의 수요 에 따라 우 리 는 다음 과 같은 데이터 베 이 스 를 설정 합 니 다.
CREATE TABLE `app_margin`.`tb_status` (
`appid` int(10) UNSIGNED NOT NULL,
`freeze` int(10) NOT NULL DEFAULT 0,
`create_time` datetime NOT NULL,
`change_time` datetime NOT NULL,
PRIMARY KEY (`appid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `app_margin`.`tb_account_earn` (
`appid` int(10) UNSIGNED NOT NULL,
`create_time` datetime NOT NULL,
`balance` bigint(20) NOT NULL,
`change_time` datetime NOT NULL,
`seqid` int(10) NOT NULL DEFAULT 500000000,
PRIMARY KEY (`appid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `app_margin`.`tb_bill` (
`id` int AUTO_INCREMENT NOT NULL,
`bill_id` int(10) NOT NULL,
`amt` bigint(20) NOT NULL,
`bill_info` text,
`bill_user` char(128),
`bill_time` datetime NOT NULL,
`bill_type` int(10) NOT NULL,
`bill_channel` int(10) NOT NULL,
`bill_ret` int(10) NOT NULL,
`appid` int(10) UNSIGNED NOT NULL,
`old_balance` bigint(20) NOT NULL,
`price_info` text,
`src_ip` char(128),
PRIMARY KEY (`id`),
UNIQUE KEY `unique_bill` (`bill_id`,`bill_channel`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `app_margin`.`tb_assign` (
`id` int AUTO_INCREMENT NOT NULL,
`assign_time` datetime NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `app_margin`.`tb_price` (
`name` char(128) NOT NULL,
`price` int(10) NOT NULL,
`info` text NOT NULL,
PRIMARY KEY (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `app_margin`.`tb_applock` (
`appid` int(10) UNSIGNED NOT NULL,
`lock_mode` int(10) NOT NULL DEFAULT 0,
`change_time` datetime NOT NULL,
PRIMARY KEY (`appid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
INSERT `app_margin`.`tb_assign` (`id`,`assign_time`) VALUES (100000000,now());
상세 한 설명 은 다음 과 같다.tb_status 응용 상태 표.계 정 이 동결 되 었 는 지,계 정의 유형 이 무엇 인지 책임 집 니 다.(실제 수 요 는 두 가지 계 정 이 있 을 수 있 습 니 다.여 기 는 간단 하기 때문에 열거 되 지 않 았 습 니 다)
appid 응용 id
동결 여부
create_시간 생 성 시간
change_time 마지막 수정 시간
tb_account_earn 응용 계 정 잔액 표
appid 응용 id
balance 잔액(단 위 는 점수 이 고 소수 로 저장 하지 마 세 요.소수 자체 가 정확 하지 않 기 때 문 입 니 다.또한 php 는 64 비트 컴퓨터 에서 만 bigint 를 지원 할 수 있 습 니 다)
create_시간 생 성 시간
change_time 마지막 수정 시간
seqid 작업 시퀀스 번호(동시 다발 방지,매번 update+1)
tb_assign 분배 유수 id 의 시계,tbbill 의 billid 는 tb 가 있어 야 합 니 다.할당
id 자체 증가 id
create_시간 생 성 시간
tb_bill 유량계.모든 작업 흐름 을 기록 하 는 일 을 맡 고 있 습 니 다.여기 빌id 는 메 인 키 가 아 닙 니 다.같은 bill 때 문 입 니 다.id 지불 과 스크롤 백 두 개의 흐름 이 있 을 수 있 습 니 다.
id 자체 증가 시퀀스 번호
bill_id 흐름 번호
amt 작업 금액(이것 은 양음 을 구별 해 야 하 는데 주로 selectall 을 위해 특정한 시간의 금액 변 화 를 직접 계산 할 수 있 습 니 다)
bill_info 작업 에 대한 자세 한 정보,예 를 들 어 웹 서버 3 대,db 2 대
bill_사용자 조작 사용자
bill_시간 흐름 시간
bill_type 흐름 유형
bill_channel 흐름 원,예 를 들 어 충전,지불,스크롤 백,결제 또는 기타
bill_ret 흐름 의 반환 코드 는 처리 되 지 않 음,성공,실 패 를 포함 하고 여기 의 논 리 는 뒤에서 설명 할 것 입 니 다.
appid 응용 id
old_balance 작업 발생 전 계좌 잔액
price_info 작업 발생 시 지불 되 는 물품 의 단 가 를 기록 합 니 다.
src_ip 클 라 이언 트 ip
tb_price 단가 표,기계 단가 기록
name 기계 유일한 표식
가격
정보 설명
tb_applock 잠 금 표 입 니 다.이것 은 특정한 응용 프로그램 에 대해 작성 작업 디자인 을 하 는 것 을 피하 기 위해 서 입 니 다.구체 적 인 코드 는 뒤에서 보 여 줍 니 다.
appid 응용 id
lock_mode 잠 금 상태.0 이면 잠 금,1 이면 잠 금.
change_time 마지막 수정 시간
OK,라 이브 러 리 가 디자인 된 후에 우 리 는 가장 전형 적 인 몇 가지 조작 을 살 펴 보 겠 습 니 다.
지불 조작
나 는 지금 내 가 실현 하고 있 는 방식 만 열거 했다.아마도 가장 좋 은 것 은 아 닐 것 이다.그러나 가장 경제적 이 고 수 요 를 만족 시 켜 야 한다.
먼저 호출 자 에 게 논 리 는 다음 과 같다.
그 다음 에 대응 하 는 결제 시스템 내부 논 리 는 다음 과 같다.
자주 사용 하 는 오류 반환 코드 는 다음 과 같 으 면 충분 할 것 입 니 다.
$g_site_error = array(
-1 => ' ',
-2 => ' ',
-3 => ' ',
0 => ' ',
1 => ' ',
2 => ' ',
3 => ' ',
4 => ' ',
5 => ' ',
6 => ' ',
);
0 이상 의 오 류 는 모두 논리 적 오류 라 고 할 수 있 고 지불 작업 을 수행 할 때 호출 자 는 물 흐름 을 기록 하지 않 아 도 된다.계 정 이 바 뀌 지 않 았 기 때문이다.0 이하 의 오 류 는 시스템 내부 오류 입 니 다.데이터 변경 이 발생 했 는 지 모 르 기 때문에 호출 자 와 지불 시스템 은 모두 흐름 을 기록 해 야 합 니 다.
0 과 같은 귀환 은 성공 을 의미 하 며 양쪽 에 도 흐 르 는 물 을 기록 해 야 한다.
결제 시스템 내부 에서 먼저 흐름 을 기록 한 다음 에 계 정 을 업데이트 하 는 방식 을 사용 하 는 것 도 이유 가 있다.쉽게 말 하면 흐름 을 잃 지 않도록 하 는 것 이다.
마지막 으로 정리 해 보면 이런 돈 을 먼저 공제 하고 화물 을 발송 하 며 문제 가 생기 면 다시 굴 러 가 는 방식 은 일종 의 모델 이다.또 하 나 는 미리 공제 하고 나중에 발송 하 며 문제 가 생기 지 않 으 면 지불 확인 을 통 해 공제 하고 문제 가 생기 면 지불 스크롤 백 을 통 해 취소 하 며,미리 공제 한 후 오랫동안 아무런 확인 도 하지 않 으 면 금액 이 자동 으로 굴 러 간다.
2.계 정 잠 금 의 실현
여기 서 데이터 뱅 크 의 잠 금 체 제 를 이용 하여 구체 적 인 논 리 는 말 하지 않 겠 습 니 다.코드 는 다음 과 같 습 니 다.
class AppLock
{
function __construct($appid)
{
$this->m_appid = $appid;
//
$this->get();
}
function __destruct()
{
$this->free();
}
public function alloc()
{
if ($this->m_bGot == true)
{
return true;
}
$this->repairData();
$appid = $this->m_appid;
$ret = $this->update($appid,APPLOCK_MODE_FREE,APPLOCK_MODE_ALLOC);
if ($ret === false)
{
app_error_log("applock alloc fail");
return false;
}
if ($ret <= 0)
{
app_error_log("applock alloc fail,affected_rows:$ret");
return false;
}
$this->m_bGot = true;
return true;
}
public function free()
{
if ($this->m_bGot != true)
{
return true;
}
$appid = $this->m_appid;
$ret = $this->update($appid,APPLOCK_MODE_ALLOC,APPLOCK_MODE_FREE);
if ($ret === false)
{
app_error_log("applock free fail");
return false;
}
if ($ret <= 0)
{
app_error_log("applock free fail,affected_rows:$ret");
return false;
}
$this->m_bGot = false;
return true;
}
function repairData()
{
$db = APP_DB();
$appid = $this->m_appid;
$now = time();
$need_time = $now - APPLOCK_REPAIR_SECS;
$str_need_time = date("Y-m-d H:i:s", $need_time);
$db->where("appid",$appid);
$db->where("lock_mode",APPLOCK_MODE_ALLOC);
$db->where("change_time <=",$str_need_time);
$db->set("lock_mode",APPLOCK_MODE_FREE);
$db->set("change_time","NOW()",false);
$ret = $db->update(TB_APPLOCK);
if ($ret === false)
{
app_error_log("repair applock error,appid:$appid");
return false;
}
return true;
}
private function get()
{
$db = APP_DB();
$appid = $this->m_appid;
$db->where('appid', $appid);
$query = $db->get(TB_APPLOCK);
if ($query === false)
{
app_error_log("AppLock get fail.appid:$appid");
return false;
}
if (count($query->result_array()) <= 0)
{
$applock_data = array(
'appid'=>$appid,
'lock_mode'=>APPLOCK_MODE_FREE,
);
$db->set('change_time','NOW()',false);
$ret = $db->insert(TB_APPLOCK, $applock_data);
if ($ret === false)
{
app_error_log("applock insert fail:$appid");
return false;
}
//
$db->where('appid', $appid);
$query = $db->get(TB_APPLOCK);
if ($query === false)
{
app_error_log("AppLock get fail.appid:$appid");
return false;
}
if (count($query->result_array()) <= 0)
{
app_error_log("AppLock not data,appid:$appid");
return false;
}
}
$applock_data = $query->row_array();
return $applock_data;
}
private function update($appid,$old_lock_mode,$new_lock_mode)
{
$db = APP_DB();
$db->where('appid',$appid);
$db->where('lock_mode',$old_lock_mode);
$db->set('lock_mode',$new_lock_mode);
$db->set('change_time','NOW()',false);
$ret = $db->update(TB_APPLOCK);
if ($ret === false)
{
app_error_log("update applock error,appid:$appid,old_lock_mode:$old_lock_mode,new_lock_mode:$new_lock_mode");
return false;
}
return $db->affected_rows();
}
//
public $m_bGot = false;
public $m_appid;
}
잠 금 문 제 를 방지 하기 위해 잠 금 을 가 져 오 는 논리 에 시간 초과 판단 을 넣 었 으 니 코드 를 보면 알 수 있 을 것 입 니 다.회계 논리
위의 시스템 에 따라 설계 하면 장 부 를 맞 출 때 양쪽 을 맞 추 면 성공 합 니 다(즉 빌ret=0)의 흐 르 는 물 만 있 으 면 됩 니 다.완전히 일치 하면 계 정 은 문제 가 없 을 것 입 니 다.일치 하지 않 으 면 문 제 를 찾 아야 합 니 다.
계좌 의 정확성 을 확보 하 는 데 있어 서 동료 들 도 저 에 게 예전 에 회사 에서 했 을 때 어떤 조작 이 있 으 면 먼저 흐름 표 에 있 는 모든 흐름 기록 을 취하 고 amt 의 가 치 를 누적 하여 얻 은 결과 가 잔액 과 같 는 지 확인 하 라 고 말 했 습 니 다.다 르 면 문제 가 생 긴 것 같 습 니 다.
select sum(amt) from tb_bill where appid=1;
그래서 이것 도 내 가 흐름 표 에서 amt 필드 는 플러스 와 마이너스 를 구분 해 야 하 는 이유 이다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
laravel에 yo에서 angularJs&coffeescript를 사용할 수 있도록 한다.먼저 yo 명령을 사용할 수 있어야하므로 아래에서 설치 global에 설치한 곳에서 laravel의 프로젝트 루트로 이동. 클라이언트 코드를 관리하는 디렉토리를 만들고 이동합니다. 클라이언트 환경 만들기 이것으로 히...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.