多级分销对接第三方API获取数据系统的优化

时间:2022-09-24 23:37:30

最近在做一个基于有赞的多级分销管理系统,所有成员的店面均在有赞商城,使用有赞API获得他们的业绩,但是有赞提供的分销只有一级,故制作该系统。考虑到减轻工作量,理清层次关系,采用了OOP设计方法,将数据库,表封装为基类,分销成员,店面等继承表。

但是在列出销售量报表和分销商的时候出现了严重性能问题,由于分销商的业绩奖励是与其下级分销商挂钩的,故封装数据库的时候,进行了DFS遍历来获得所有分销商的关系树,然而,在列出销售报表的时候却并不需要这样的关系,DFS在php语言上的时间花销极大,导致一个页面打开需要10s以上的时间,故对其进行第一步优化,在数据库的封装函数中设置DFS开关:

这个是Database类的部分实现,其中部分敏感数据已隐藏。

<?php
namespace System;
require_once('KdtApiClient.php');
class Database
{
const db_adr="";
const db_usr="";
const db_pwd="";
const db_db="";
public $member=array();
public function init($dfs=true,$store=true)
{
$mysqli=new \mysqli(self::db_adr,self::db_usr,self::db_pwd,self::db_db);
if($mysqli->connect_error) throw new Exception('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
$result=$mysqli->query("select `id` from member_new");
$row=$result->fetch_array();
$i=0;
while($row)
{
$this->member[$i]=new Member($row[0],$dfs,$store);
$row=$result->fetch_array();
$i++;
}
$mysqli->close();
}
static public function doQuery($string)
{
$mysqli=new \mysqli(self::db_adr,self::db_usr,self::db_pwd,self::db_db);
if($mysqli->connect_error) throw new Exception('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
return $mysqli->query($string);
}
static public function querySell($start,$end)
{}
}

member类是继承自Table:

class Table
{
public $data=array();
protected $table_name;
public function __construct($id)
{
$this->data['id']=$id;
$mysqli=new \mysqli(Database::db_adr,Database::db_usr,Database::db_pwd,Database::db_db);
if($mysqli->connect_error) throw new Exception('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
$result=$mysqli->query("select * from ".$this->table_name." where `id`=$id");
$row=$result->fetch_assoc();
$this->data=$row;
$mysqli->close();
}
public function updateAll() //Do NOT CHANGE ID!!!
{
reset($this->data);
while($data=each($this->data))
{
$querystring="update ".$this->table_name." set `".$data[0]."`='$data[1]' where `id`='".$this->data['id']."'";
Database::doQuery($querystring);
}
reset($this->data);
}
public function update($key)
{
$querystring="update ".$this->table_name." set `$key`='".$this->data[$key]."' where `id`='".$this->data['id']."'";
Database::doQuery($querystring);
}
public function set($key,$data) //recommended
{
$this->data[$key]=$data;
$this->update($key);
}
public function get($key) //recommended
{
return $this->data[$key];
}

}

封装了对表的基本操作,简化以后的代码编写.下面member类的构造函数可以完成DFS功能,加设开关参数后,可以在某些场合不试用DFS而大大提升效率:

class Member extends Table
{
protected $table_name="member_new";
public $infer=array();
public $store=array();
public function __construct($id,$dfs=true,$store=true)
{
parent::__construct($id);
$mysqli=new \mysqli(Database::db_adr,Database::db_usr,Database::db_pwd,Database::db_db);
if($mysqli->connect_error) throw new Exception('Connect Error (' . $mysqli->connect_errno . ') ' . $mysqli->connect_error);
if($dfs){
$result=$mysqli->query("select `id` from ".$this->table_name." where `super`=".$this->data['id']);
if($result){
$row=$result->fetch_array();
$i=0;
while($row)
{
$this->infer[$i]=new Member($row[0]);
$row=$result->fetch_array();
$i++;
}
}
}
if($store)
{
$result=$mysqli->query("select `id` from store_new where `member`=".$this->data['id']);
if($result){
$row=$result->fetch_array();
$i=0;
while($row)
{
$this->store[$i]=new Store($row[0]);
$row=$result->fetch_array();
$i++;
}
}
}
$mysqli->close();
}

(部分敏感函数已隐藏)

另外,在对前端的AJAX响应的php脚本中,加入缓存的支持,由于有赞的api调用速度较慢,然而这种分销商城的数据对实时性的要求并不是很高,故采用服务器缓存的方式来减少与有赞通讯这部分导致的速度减缓.另外,本地化的对象代替从远程数据库读取信息,也减少了查询数据库的开支.Cache对象的实现如下,将对象的序列化代码存于服务器本地:

<?php
namespace System;
class Cache
{
public function __construct()
{
}

static public function readCache($string)
{
error_reporting(1);
$file=fopen($string.".ser","r");
if(!$file)return false;
$ser=fread($file,filesize($string.".ser"));
fclose($file);
$array=array();
$array=unserialize($ser);
if(time()-$array['time']>3600*24)return false;
return $array['data'];
}

static public function updateCache($string,$data)
{
$array=array();
$array['time']=time();
$array['data']=$data;
$file=fopen($string.".ser","w");
fwrite($file,serialize($array));
fclose($file);
}
}

后端AJAX响应页面根据Cache类的反馈选择获取本地数据,或是请求服务器更新本地数据:

<?php
require_once('System/db.php');
require_once('System/cache.php');
use \System\Database;
use \System\Cache;

switch($_GET['action'])
{
case 'num':
$result=Database::doQuery("select count(*) from member_new");
$row=$result->fetch_array();
echo $row[0];
exit(0);
case 'get':
if($array=Cache::readCache("member"))
{
echo json_encode($array);
}
else
{
$db=new Database();
$db->init(false,true);
$arr=array();
for($i=0;$i<count($db->member);$i++)
{
$arr[$i]=array();
$arr[$i]=$db->member[$i]->data;
$arr[$i]['password']=null;
$arr[$i]['name']=iconv("GBK","utf-8",$arr[$i]['name']);
$arr[$i]['nickname']=iconv("GBK","utf-8",$arr[$i]['nickname']);
$arr[$i]['sell']=$db->member[$i]->getSell();
}
Cache::updateCache("member",$arr);
echo json_encode($arr);
}
exit(0);

经过以上优化,原本响应时间在15s左右的页面,现在响应时间为0.5s左右.