仓酷云

标题: PHP网站制作之一个典范PHP付出体系的设计与完成 [打印本页]

作者: 老尸    时间: 2015-2-3 23:30
标题: PHP网站制作之一个典范PHP付出体系的设计与完成
左手拿着MOTOLOLA右手拿着NOKIA,要多潇洒,有多潇洒,哈哈,终于学会了,但是可能这个时候,又会有人不经意的拍拍肩膀对你说:哥们,别高兴的太早,你还是菜鸟,离学会还差着一大截呢!     
  因为公司营业需求,花两周工夫完成了一个小型的付出体系,麻雀虽小五脏俱全,各类必需的模块如账户加锁,事务性包管,流水对帐等都是有完全完成的,全部开辟过程当中有良多经历堆集,再加上在网上搜刮了一下,大局部都是些研讨性的论文,对实践利用价值不大,所以此次特地拿出来和人人分享一下。
  这个体系可以用作小型付出体系,也能够用做第三方使用接入开放平台时的付出流水体系。
  本来的需求对照担任,我简化一点说:
  针对下面的需求,咱们设置以下数据库:
  1. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
复制代码
  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());
复制代码
具体注释以下:

  OK,库表设计出来以后,咱们就来看一下最典范的几个操作.
  一. 付出操作
  我这里只列出了我今朝完成的体例,能够不是最好的,但应当是最经济又知足需求的。
  先说挪用方这里,逻辑以下:
  
PHP网站制作之一个典范PHP付出体系的设计与完成
登录/注册后可看大图

  然后对应的付出体系外部逻辑以下(只列出付出操作,回滚逻辑差不多,流水反省是要反省对应的付出流水是不是存在):
  
PHP网站制作之一个典范PHP付出体系的设计与完成
登录/注册后可看大图

  经常使用的毛病前往码能够以下就足够了:
  1. 1 2 3 4 5 6 7 8 9 10 11 12 13 14
复制代码
  1. $g_site_error = array( -1 => '办事
    器忙碌
    ', -2 => '数据库读取毛病
    ', -3 => '数据库写入毛病
    ',   0 => '胜利
    ',   1 => '没无数
    据', 2 => '没有权限', 3 => '余额缺乏
    ', 4 => '账户被解冻
    ', 5 => '账户被锁定', 6 => '参数毛病
    ', );
复制代码
  而在付出体系外部,之所以采取先写入流水,再停止账户更新的体例也是有缘由的,复杂来讲就是尽可能防止丧失流水。
  最初总结一下,这类先扣钱,再发货,出成绩再回滚的体例是一种形式;还有一种是先预扣,后发货,没有出成绩则挪用付出确认来扣款,出了成绩就挪用付出回滚来作废,假如预扣以后很长工夫不做任何确认,那末金额会主动回滚。
  二. 账户锁定的完成
  这里使用了数据库的加锁机制,详细逻辑就不说了,代码以下:
  1. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164
复制代码
  1. 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; }
复制代码
为了避免逝世锁的成绩,获得锁的逻辑中到场了超不时间的判别,人人看代码应当就可以看懂
  三. 对帐逻辑
  假如依照下面的体系来设计,那末对帐的时分,只需对一下双方胜利(即bill_ret=0)的流水便可,假如完整分歧那末账户应当是没有成绩的,假如纷歧致,那就要去查询题了。
  关于包管账户准确性这里,也有同事跟我说,之前在公司做的时分,是接纳只需有任何写操作之前,都先取一下贱水表中一切的流水纪录,将amt的值累加起来,看失掉的了局是不是和余额不异。假如不不异应当就是出成绩了。
  1. 1
复制代码
  1. select sum(amt) from tb_bill where appid=1;
复制代码
所以这也是为何我在流水表中,amt字段是要辨别正负的缘由。
  OK,整篇文章写的很长,但愿对保持读完的同窗有所匡助。
一下弹出N多页面!很明显,你的留言本并没有做好安全防范,被人用JS代码小小的耍了一下,我很同情你这个时候的感受,但是没有别的办法了,继续努力吧!
作者: 飘飘悠悠    时间: 2015-2-4 00:03
使用 jquery 等js框架的时候,要随时注意浏览器的更新情况,不然很容易发生框架不能使用。
作者: 飘灵儿    时间: 2015-2-9 07:39
最后介绍一个代码出错,但是老找不到错误方法,就是 go to wc (囧),出去换换气没准回来就找到错误啦。
作者: 简单生活    时间: 2015-2-11 08:43
学好程序语言,多些才是王道,写两个小时代码的作用绝对超过看一天书,这个我是深有体会(顺便还能练打字速度)。
作者: 兰色精灵    时间: 2015-2-26 06:44
环境搭建好,当你看见你的浏览器输出“it works\\\\\\\"时你一定是喜悦的。在你解决问题的时候,我强烈建议多读php手册。
作者: 仓酷云    时间: 2015-3-6 21:40
首推的搜索引擎当然是Google大神,其次我比较喜欢 百度知道。不过搜出来的结果往往都是 大家copy来copy去的,运气的的概率很大。
作者: 谁可相欹    时间: 2015-3-9 04:00
开发工具也会慢慢的更专业,每个公司的可能不一样,但是zend studio是个大伙都会用的。
作者: 乐观    时间: 2015-3-10 21:34
爱上php,他也会爱上你。
作者: 只想知道    时间: 2015-3-17 10:29
基础有没有对学习php没有太大区别,关键是兴趣。
作者: 小魔女    时间: 2015-3-24 07:20
先学习php和mysql,还有css(html语言很简单)我认为现在的效果比以前的方法好。
作者: 若天明    时间: 2015-4-13 01:27
要进行开发,搭建环境是首先需要做的事,windows下面我习惯把环境那个安装在C盘下面,因为我配的环境经常出现诡异事件,什么事都没做环境有的时候就不能用啦。
作者: 海妖    时间: 2015-4-22 09:13
这些都是最基本最常用功能,我们这些菜鸟在系统学习后,可以先对这些功能深入研究。
作者: 不帅    时间: 2015-4-27 22:07
环境搭建好,当你看见你的浏览器输出“it works\\\\\\\"时你一定是喜悦的。在你解决问题的时候,我强烈建议多读php手册。
作者: 柔情似水    时间: 2015-5-4 02:37
php是动态网站开发的优秀语言,在学习的时候万万不能冒进。在系统的学习前,我认为不应该只是追求实现某种效果,因为即使你复制他人的代码调试成功,实现了你所期望的效果,你也不了解其中的原理。
作者: 爱飞    时间: 2015-6-9 03:05
再就是混迹于论坛啦,咱们的phpchina的论坛就很强大,提出的问题一般都是有达人去解答的,以前的帖子也要多看看也能学到不少前辈们的经验。别的不错的论坛例如php100,javaeye也是很不错的。
作者: 老尸    时间: 2015-6-27 22:23
使用zendstdio 写代码的的时候,把tab 的缩进设置成4个空格是很有必要的
作者: 第二个灵魂    时间: 2015-7-10 15:30
最后介绍一个代码出错,但是老找不到错误方法,就是 go to wc (囧),出去换换气没准回来就找到错误啦。
作者: 金色的骷髅    时间: 2015-7-16 04:42
我要在声明一下:我是个菜鸟!!我对php这门优秀的语言也是知之甚少。但是我要在这里说一下php在网站开发中最常用的几个功能:
作者: 小女巫    时间: 2015-7-28 02:11
当留言板完成的时候,下步可以把做1个单人的blog程序,做为目标,




欢迎光临 仓酷云 (http://ckuyun.com/) Powered by Discuz! X3.2