|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
" P( S- ^7 l& h+ d1 W/ p/ JMysql中的锁语法:
3 C. W' H4 [9 L6 s" ~LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】4 k; i8 }/ ?8 b# k
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 A0 M( U; j9 ?$ H* `# T0 o
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
+ r q$ E8 _2 J1 g" o }7 q注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :( q& s- I5 Q& ?7 I
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
6 |1 t8 d* ?9 v' o* A5 o测试时,有个文件就行,叫什么名无所谓 总结:$ o4 h# p. e7 @8 [0 Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
* ~+ [7 C/ i3 W3 \4 M: v0 k1. 高并发下单时,减库存量时要加锁
) z. @+ {2 R7 |3 O2. 高并发抢单、抢票时要使用 Mysql锁示例: - /* g K9 W' D1 C v7 J- E+ [9 z
- 模拟秒杀活动-- 商品100件
# U6 f' ~4 c) v% L; Z - CREATE TABLE ta
+ c7 I' p# i" P- W - (
& P s, x* a! r9 D; ^/ N. u- [) @ - id int comment '模拟100件活动商品的数量'! F% c3 k$ Z2 F$ b
- );
5 j+ E) W/ }# [8 l! Z - INSERT INTO ta VALUES(100);5 F4 N5 t4 s6 g8 |
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
# ?$ [) ^$ U( a. B1 { - */
& n1 X j* B4 |* l -
* @' b8 o' N( {0 l1 ?% T7 s* j. i8 l - // 关闭错误报告3 b0 D# M( l+ V3 N' [5 i. G( y
- error_reporting(0); - x) C3 e. K* K, L
- 7 U7 c4 k1 U* f& o4 q9 B
- $dbhost = 'localhost:3306'; // mysql服务器主机地址) H) l8 j. C! ]# n2 C6 p; e y" `1 L
- $dbuser = 'root'; // mysql用户名& v* L5 l8 [9 s9 x1 {5 v
- $dbpass = 'root'; // mysql用户名密码" x" l0 C) `8 h# g4 q& `
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);, \! l" s y1 I
- if(! $conn )/ C" \8 ], r+ ]( t" T; q
- {
! o" ^0 a6 V1 H' x2 O - die('连接失败: ' . mysqli_error($conn));
% N+ P8 c# T; P9 y' L: T - }8 T U/ C' }( [' h5 O# X. D
- // 设置编码,防止中文乱码
# [; @8 [, `7 A0 }, L h - mysqli_query($conn , "set names utf8");7 `- p' R* \# C5 G% C
- mysqli_select_db( $conn, 'temp' ); 9 I! y _* p0 F; M- F' d
, F" n3 G O' w& d. C& n: u, B- # mysql 锁 6 O3 c! y1 {7 G5 W) e9 M3 P, q
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 W6 K n* Z# S7 I8 l- H. l, {. E: w# g
- $rs = mysqli_query($conn , 'SELECT id FROM a'); $ J# H/ r9 R6 V/ f
- $id = mysqli_result($rs, 0, 0);
8 I$ L; r. t2 y2 z! L) i5 n: R5 ] - if($id > 0) 5 C9 Q; `* V) A4 c' {' J- N
- { 8 g9 u! H" k- y {
- --$id;
' E5 u2 s3 \# `! p - mysqli_query($conn , 'UPDATE a SET id='.$id);
' a9 c* ~3 d( @2 y - }
! X% h% S5 A' i/ E" v1 x - * f4 [1 ^# A+ ]8 m+ p
- # mysql 解锁
' r0 ]5 r# m4 v+ f - mysqli_query($conn , 'UNLOCK TABLES');: Z, m7 U4 v7 J2 ]# c
- //查询解锁后的id值
1 X$ x3 K8 g* x! j - // $res = mysqli_query($conn , 'SELECT id FROM ta');
6 l# j+ v$ C; f. C3 s) v$ n7 ]6 W - // while($row = mysqli_fetch_assoc($res))- ^9 R; k" C9 `1 q7 J
- // {2 I- j' L6 B: Y3 Y
- // $id = $row['id'];" W$ B, [& R6 O$ s9 B+ p! P
- // }
! P: Y* f* B/ G5 D$ h2 T5 _1 ? - // echo $id;
复制代码 / L- L% S& q4 n) ?! j( e
7 s/ y- @( J: V% p) D5 N, Q$ m
, ^/ v: }6 J; Y8 ]9 f3 J4 OPHP文件锁示例: - /*
2 W8 ~" i- Q! M# m - 模拟秒杀活动-- 商品100件) }9 x6 T7 H9 b S
- CREATE TABLE ta
# D7 p: L' k5 ]+ F1 \. k - (- _6 i3 U( i2 s7 y$ T* h$ ^1 `
- id int comment '模拟100件活动商品的数量'
; K; p9 g5 N% I& C/ D - );
) G' J9 r b% Z- f% B - INSERT INTO ta VALUES(100);
% g& c8 G+ w- s( o4 Z - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
9 ~- ~; t% i, _, B% Z" \ - */
7 X* p# ~$ X. P1 P! t: h1 b' E - % p. i$ M" d p4 |
- // 关闭错误报告
1 T [. n$ t p1 P - error_reporting(0); . q2 I q, l" l+ M0 D$ x& Q
: n+ d' } O8 X% D1 ]0 f- $dbhost = 'localhost:3306'; // mysql服务器主机地址& t* F! M6 B8 L* ~3 v4 n
- $dbuser = 'root'; // mysql用户名
. y* \, u, g; ]$ p* S - $dbpass = 'root'; // mysql用户名密码
" {" L( T6 o* L/ N" Z - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
~" w, w2 B: V [ - if(! $conn )# \: o% `9 r" r
- {
) Q) }: F" ~$ H$ r% V - die('连接失败: ' . mysqli_error($conn));
& a* E6 m7 Z/ l* ]8 V* A - }! I* c4 ^# P: V+ l7 V; [+ Y
- // 设置编码,防止中文乱码
# `% i1 _: E* B$ w+ V1 l - mysqli_query($conn , "set names utf8");3 z* y6 r" p$ J! p/ ?
- mysqli_select_db( $conn, 'temp' );
% [6 L, d- J- {2 E& n$ a7 B - N5 g) B \- q- w: G" c
- # php中的文件锁 7 W: a% J, |: w9 v7 T. B- [; M
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 * X, }( J. Y6 w; O
- flock($fp, LOCK_EX);// 排他锁
$ W( t+ ~* j9 V1 o+ m
1 Y2 d" W# D7 x+ @1 j% o6 L- $retval = mysqli_query($conn ,'SELECT id FROM ta');
, v. O! m. s. C$ y4 J. o( `2 M- | - while($row = mysqli_fetch_assoc($retval))* z3 E% X. V, S% i) @3 {: k
- {
+ I: k4 U1 a4 \, c* A% n% H - $id = $row['id'];
- o+ x! h; U" i1 \- ?$ H - }8 |! Z5 F" d* c( k; ^, Q
- " G+ \& R( R: u; v% d7 N s
- if($id > 0) 0 O* j: N) G: b6 D" O {, B) x
- { 9 M( |( y8 [7 R9 S+ R
- --$id; 5 n1 g5 T& _& M$ B
- mysqli_query($conn ,'UPDATE ta SET id='.$id); 9 w+ O+ c5 d4 I* U* [9 M5 ~
- }
' R3 h* P. Z& Z8 p' X+ E/ T: b - # php的文件锁,释放锁 / h& S1 a% o, y! B
- flock($fp, LOCK_UN);
; n/ `$ _+ N: v5 @* L - fclose($fp);
8 Y3 A' j1 S+ h( n' C/ b6 d' \* A
3 X: ~2 B8 A( G- // $res = mysqli_query($conn , 'SELECT id FROM ta');
+ T: B+ w, g/ S* T0 }% p - // while($row = mysqli_fetch_assoc($res))8 Q3 U4 p; ?" {. B9 e" k
- // {
8 R% F1 T( M5 k( Q - // $id = $row['id'];
) u) O/ n. z3 J r. h: L6 M4 ` - // }
. i& m( y u8 c% G+ @& O - // echo $id;
复制代码 5 i/ a7 V9 w1 Y2 i- L" C
+ J. d* c* P* G) j+ @3 b) F抢券活动实例: - public function envelopeSnatching(){
3 z; F" _' M3 ?& e$ \8 E - $lingqu = $_POST['type'];' c& h. e' B U1 i
- $uid=session('u_id');//用户id% l2 P) U; j. L0 p0 R
- if(!$uid){: _! E7 X* }1 S' V
- $data['msg']='您没登录,请先登录!';5 m5 u( m$ ?! g- {5 G
- }else if(date('Y-m-d') != '2017-12-12'){0 f3 r+ l \ X7 C
- $data['msg']='不在活动时间内!';
) ]2 `( s! z+ V7 }/ U. D* D7 A - }else{
5 N1 c: t% [/ i. o% V6 H - $hours=date('H');//当前小时数
: b' e# y2 T- A% Q - if($hours > '09' || $hours > '17'){3 C" |3 f8 G+ N1 f
& M6 i4 X& K. P* A" Q- if($lingqu == 1 || $lingqu ==2){//点击10点的
% J- O" {9 ]5 a8 ]" d - if($lingqu == 1){8 L5 W' c9 `2 x
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过4 d( b/ L c" B- c
- if($hours > '09'){4 [7 T6 R' p$ T
- $num=mt_rand(25,28);//优惠券金额
& B$ D; s3 V( ~+ ] - $id=1;# s' W4 ~* F/ t
- }
: |" O/ f+ K9 j; k3 A: h& h - }else if($lingqu == 2){
5 Q) A/ ?2 ~' \ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
9 ~0 ~+ J6 z* R' V8 P3 Q0 U8 A: P - if($hours > '17'){
! l _% X' s9 S% ?( Y) Z+ N' A - $num=mt_rand(50,55);//优惠券金额
& n, B. U% s. Y - $id=2;( Z1 D7 ?" Y+ t' c0 t
- }7 v- m$ T$ Z3 H; @8 E2 q
- }+ \1 k# ]5 b4 p
- if(!$id){
\8 r1 L! M4 t. E3 [2 V: A - $data['msg']='时间还没到,晚点再来吧。';8 h* C3 L7 _/ D) b
- }else{
+ f6 B! H$ d/ x0 r' J% z$ q - if($is_lingqu){
; I- \* k3 K% q# E% R" s - $data['msg']='你已经领取过了,留点给别人吧!';
, q2 e( Z) n! Z* Y4 Z - }else{
& U$ @: p9 h: `+ G0 T% U - //锁表- o/ ?/ F8 X6 y) P6 V3 ]
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');; l) ~% A( c( P. c" e
- $active=M('active_num')->where(array('id'=>$id))->find();4 d9 \* U# Q0 g* B F1 f) a
- if($active > 0){2 t8 ~. S% A& K$ V
- //开启事务, D0 Z2 n' A I6 x( z
- M()->execute('start transaction');
, o9 M) Q. |. i; p* V$ K - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));9 m' {8 v0 m: G( u, V3 P8 K2 S
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));3 X- h0 G2 N+ M" Y
- $members_preferential = M('members_preferential');
! N [1 a$ v8 {5 Z4 _ - //对应投资金额,
; E8 m' D# U: r" M - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
4 |5 D- L( M/ E7 ~( G9 J - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');) u' S# a9 _! g6 W% Q3 ~
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
* v v0 h- @! Z# p' r- J K - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券2 t# {6 k+ W7 L$ M x [
- if($save && $add && $add2){
: {2 X& K0 \: Q0 A1 a8 H' _ - //事务提交& t4 _ o `0 N( J
- M()->execute('commit');& o: \9 `5 [. N& t3 P2 S& c
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
' ~& q& |: B1 q- {$ o - }else{+ q3 d' Y" _ N _8 Z* }) p G
- //回滚
, |/ N% W! J" @ N: ~ - M()->execute('rollback');
3 z! h9 x# {% s. a; z3 G2 v - $data['msg']='未知错误!';
6 r" D/ R, U7 u2 r - }: {: Y. S# n5 u s+ s- G6 v$ _% M
- }else{
8 f& B* z" W# j+ y: V% R8 r - $data['msg']='红包已领完,你来晚了!';) R% [0 T) i* h$ w: F( G
- }0 W- ~% {. R4 C* Z
- M()->execute('UNLOCK TABLES');
; N2 d \) N/ m% g5 Z - }
. L; {* w0 g+ N' B - }: F' K. b9 K t: P
- }else{
$ h+ U) K7 q7 ^& g2 F( ? - $data['msg']='非法操作!';! y& p* [( w; Z! j3 X2 \
- }
% i3 }4 s1 A, E9 m0 O! F& K' c% N - }else{; d: y) e7 D' d) p3 n/ x! a1 a
- $data['msg']='还没有到活动时间,请晚点再来哟!!';
- s* ]' r8 F. w - }/ a) {# p* V9 c3 _3 i( C
- }
" u/ |3 r. W; B) F- i% n. p' D! e( { - exit(json_encode($data));
$ P; M4 w/ I( B$ j0 U - }
复制代码 8 b5 U6 P: T# x" V8 M8 A( S4 a
! K, {' @, G' a. [) p, l& x& u9 y |