模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 ' ?0 u2 @ i! H- \: @2 }9 }8 [
Mysql中的锁语法:1 g. B* b- _' z* w0 K
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】2 x9 x4 j; ^* ~, m8 A: t- E
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表+ v! u* H1 w- X" \; ]
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞( _. V$ z5 O8 h" S0 v* U: H/ l4 ^5 l
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :& `8 M& k/ q, i$ A
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。1 v0 j0 B( d* ]) c! @3 J6 n
测试时,有个文件就行,叫什么名无所谓 总结:
3 H1 Z- b9 D, G% ~+ L( q- M3 L) ^/ Y项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:8 Z. Q! g; R E; c0 t& A! f
1. 高并发下单时,减库存量时要加锁
9 T6 E7 U" a; m1 \8 M. q2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*9 N9 N) V; B8 L+ d
- 模拟秒杀活动-- 商品100件
. P% I* O' H3 f - CREATE TABLE ta
1 z4 U* Z: G" e: l& ?7 ], q" N7 x - (
$ ]( W7 b! X+ U x, u - id int comment '模拟100件活动商品的数量'' R1 E6 L2 P$ A$ r
- );
- j P. E% g; @ - INSERT INTO ta VALUES(100);
' z0 `6 _: }# @' j* M - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件+ _: L2 T# D$ \1 N V& r9 f
- */
0 n( H+ k J. F - : P" _" B/ p9 g5 y, L: ] S
- // 关闭错误报告. J8 e: T0 Q n- ], M
- error_reporting(0); 7 |% z% R% I" r& N0 n
5 ]8 N" T3 q# ?1 X3 |! T0 g) r" k- $dbhost = 'localhost:3306'; // mysql服务器主机地址# s1 ?3 T( d3 }
- $dbuser = 'root'; // mysql用户名
; g2 [% ?; q/ A9 H' E" | - $dbpass = 'root'; // mysql用户名密码
# _- ?6 W; ^4 F. N2 Z- J - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);* y3 N! A' K6 d: b9 D
- if(! $conn )8 m, ? R7 _5 b6 ^% @" H
- {" C& o1 m1 w1 Y3 [" \1 x3 l7 H
- die('连接失败: ' . mysqli_error($conn));
! j# A* r' a9 r: _ t - }
0 Q! E% u- m7 P6 D, C; }. D7 C - // 设置编码,防止中文乱码
9 s" q8 n! x( f" T! \ - mysqli_query($conn , "set names utf8");
* v$ P, s4 D3 A; F9 R7 F# A - mysqli_select_db( $conn, 'temp' ); ) z+ X7 ^ N1 S3 j
# o- E8 f0 U8 z* @" d, N4 n- # mysql 锁
: r* U' [# x; F' C) L - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
) S5 q. z$ j% K) o) @) U* n% z W - $rs = mysqli_query($conn , 'SELECT id FROM a');
8 e1 `! C5 h: j. C( o - $id = mysqli_result($rs, 0, 0);
" @5 y6 u3 i8 [ s - if($id > 0)
# o! c0 m8 v& U; a) t4 j - { 5 g4 A$ X7 H; _5 A2 D
- --$id; * G T+ T2 s" K5 J: n0 x( S
- mysqli_query($conn , 'UPDATE a SET id='.$id); f' ^0 [$ |) a }, a
- }
& W5 T9 A- t7 F$ P
! b7 w A/ R8 ?1 v- # mysql 解锁 ! N% X8 w, Z, ^" ?
- mysqli_query($conn , 'UNLOCK TABLES');
5 q' z' Q8 ]3 X9 ~% z" H( i - //查询解锁后的id值4 l% F) h, A6 y+ M
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
6 R+ u/ A G( F g& Z - // while($row = mysqli_fetch_assoc($res))- t+ w8 O6 F, W
- // {' Z9 L$ G, ]. } ~! n" A* N) |$ z
- // $id = $row['id'];3 p3 ~8 m( s: h5 {6 h% o* E; ?% g
- // }. B/ q `% K) ?. _. ]
- // echo $id;
复制代码 + f- X" W# }1 }/ B7 g8 P7 q
# y" [* H. s5 B
! y8 i' _( v. NPHP文件锁示例: - /*
, @' O7 a$ ]$ _3 W' l - 模拟秒杀活动-- 商品100件6 Q% `' u- D% ~+ m8 `& d9 ~
- CREATE TABLE ta
! b5 v2 n: ^/ A' N, l - (
* s2 T, R: g7 e2 a- v7 T - id int comment '模拟100件活动商品的数量'
* x( f" F0 p) m/ h+ r) `6 k - );
% F& s$ Q/ C% S$ _# `" `: b - INSERT INTO ta VALUES(100);
& W) b* }5 Y6 a* I& k - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
6 D @' G( w6 d! D) y2 h - */
2 O) U# f: e2 h+ c1 C7 C - ; v, G2 A. z: Q& }5 @/ r
- // 关闭错误报告) b- n: D3 r0 i* d% s
- error_reporting(0); 2 i. T3 [$ ^* P) Y+ C; ~' G
6 |1 }) u" i5 W9 t- N- ?: U- $dbhost = 'localhost:3306'; // mysql服务器主机地址
) p8 q, N& X- ^ B) N; |7 F# \ - $dbuser = 'root'; // mysql用户名: u) u9 _& r p' ^
- $dbpass = 'root'; // mysql用户名密码
* q1 l% l7 H+ d4 K7 Y# `, g* _ - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);3 u$ H; p2 p: G3 J/ r- N5 l* |5 y
- if(! $conn )
}$ |' K) K, h# Y ~& } - {
* E" Q4 w4 c: i* r% I8 Z o. `# Y - die('连接失败: ' . mysqli_error($conn));
8 h9 n3 t2 f# B8 K% E - }- t/ ?# k! i9 [7 M9 K
- // 设置编码,防止中文乱码
5 Z8 h" S# d5 ^ - mysqli_query($conn , "set names utf8");
+ W. D1 c8 S7 ^ - mysqli_select_db( $conn, 'temp' ); : w' U2 j/ r- g
4 D' P' l6 h3 t- b, T {. X- # php中的文件锁
% c2 z$ A# P; Y2 c% T2 R - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : ~0 Z* _; _4 V5 S: t
- flock($fp, LOCK_EX);// 排他锁
$ I9 }% [1 i8 Z" z
, ~# H& N9 Y& F. [5 U s. N- $retval = mysqli_query($conn ,'SELECT id FROM ta'); . v$ c' I9 V% J% D
- while($row = mysqli_fetch_assoc($retval))8 @% X- _5 h% I H9 a
- {
) k( |7 ^2 T7 J4 D: m - $id = $row['id'];$ B: O0 [$ U3 N. z
- }4 P5 \8 h5 K, M0 n4 t
- $ @0 h) @6 Q s- D% X5 _
- if($id > 0)
4 q, c( R# Q, N - {
0 m4 J4 \- Y4 \2 E; a8 }; A - --$id;
% Q$ @- a, q8 t# E9 Y) ?, N4 E6 g& G - mysqli_query($conn ,'UPDATE ta SET id='.$id);
+ E) e6 L# k. @) l5 X* x/ i - } ) t1 ]6 y' j; a4 u8 a+ u
- # php的文件锁,释放锁 4 e, A/ ?& D6 ^& t K0 P
- flock($fp, LOCK_UN); 6 |& B1 h l9 B, `! W' U3 D
- fclose($fp);
! b% p( z n) w j6 ` - % y- p0 x i3 r5 E o1 P# F
- // $res = mysqli_query($conn , 'SELECT id FROM ta');8 s4 J6 ?/ t8 m
- // while($row = mysqli_fetch_assoc($res))
3 b& [- p" G- ?& ~3 s2 W - // {: F& \. q* W8 i5 {- S" m
- // $id = $row['id'];
9 G0 S! |1 f0 o$ A: `' w$ d - // }
, @3 d/ t7 ^" C, c - // echo $id;
复制代码
' ~( R1 M W& R+ I, G4 R6 J3 q9 b; s/ C, F$ ^
抢券活动实例: - public function envelopeSnatching(){4 l2 O/ f! \+ w
- $lingqu = $_POST['type'];
7 ? |1 n- t* q$ q! f0 L - $uid=session('u_id');//用户id
! G1 `' n! o% k5 l- A% \1 a - if(!$uid){. l) x* z7 j3 E! p
- $data['msg']='您没登录,请先登录!';! t0 ?+ h! z2 G9 X4 R% D4 o
- }else if(date('Y-m-d') != '2017-12-12'){
8 G( b" m8 S! r, F1 c" } - $data['msg']='不在活动时间内!';5 S6 c& ^5 L) q f5 v7 S
- }else{6 [9 b, i) o* \4 n
- $hours=date('H');//当前小时数( _4 c2 c' ?1 u! |8 X" t6 v& ]% @
- if($hours > '09' || $hours > '17'){: F" t$ V5 B& i6 i6 J& R$ ?
- 5 Y; k: c6 C' A/ E
- if($lingqu == 1 || $lingqu ==2){//点击10点的+ ]7 E1 k' [: F4 N
- if($lingqu == 1){1 Z, F( B$ [5 q- y$ d
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过 {! L6 }' _ E. F9 I
- if($hours > '09'){8 t% ~+ Y3 S% F5 z! f% U7 D
- $num=mt_rand(25,28);//优惠券金额
1 K9 m( U% u( y/ W7 _0 O - $id=1;
/ ?1 S: F' N6 }$ {& N/ w - }
, O: Q" k U c1 N* L, X2 O" L. \+ f - }else if($lingqu == 2){) w6 k3 N$ J( e3 P( R& s2 D! ~
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();( m; ^( m+ `+ K! p& R0 v
- if($hours > '17'){
5 K u) I- }) C1 C, u2 Y6 d: r - $num=mt_rand(50,55);//优惠券金额) u/ Y& O2 b/ g9 y; i
- $id=2;
" I1 A# ^1 S6 n k& i' T - }9 t% p9 m) [& J) G) J! L; F% G
- }
) l% D! ~( K- B0 U+ F- k5 Y4 L - if(!$id){- v. V- G# n. L( P1 b
- $data['msg']='时间还没到,晚点再来吧。';. y- ? [, z; Q) i; A
- }else{' z: ^( h2 r. p1 S/ l
- if($is_lingqu){# P* {; y, B6 d( J0 M$ I2 w0 U) k
- $data['msg']='你已经领取过了,留点给别人吧!';
" q# h; a; m% y# y' } - }else{ R: W7 o" p! C6 F' W
- //锁表# {- j, f0 m$ Y
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');/ u, v i1 U: c; ~' c
- $active=M('active_num')->where(array('id'=>$id))->find();, I3 W8 m0 L) m' ]
- if($active > 0){% o5 F7 E$ ~3 O2 R3 ^# Y# W1 L
- //开启事务
( C, Z( C- _! v5 W8 o; C$ ] - M()->execute('start transaction');
9 @7 j8 @! v7 r) @1 F F/ Q! a - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
" d" ]) g3 ^. | s1 m% z - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));2 p( `) v' u- ^; t" @
- $members_preferential = M('members_preferential');
6 x6 ?: a# K7 G1 p - //对应投资金额,
% f, w) Y8 b$ {# X - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));; d) e: ~4 i/ ]2 u# ]( L& s& A
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');' e: ?$ B. E; x6 l
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间! R! ?8 h1 }; R
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券; b: Z' I! @2 n6 r& F
- if($save && $add && $add2){% e9 ?8 F$ i* _5 k+ l% d# o
- //事务提交
\5 F, {2 Q' _ - M()->execute('commit');9 k3 X2 L( l: y. h
- $data['msg']='恭喜你领取了'.$num.'元优惠券';4 o5 A4 a! b5 W# _6 q: c8 J- ?& K
- }else{- V! z) N' Z' y( P) V2 w) s) P
- //回滚& t, S! E5 E/ u& I& A
- M()->execute('rollback');% U- w# h0 w+ S7 z. o
- $data['msg']='未知错误!';
8 Q8 h* `5 ~' V$ }: @# F* I B5 u( X! V - }2 y" R: _+ U4 S4 T6 N- o
- }else{ U/ Q* y9 Y: Y$ A, k. X, H$ R! O
- $data['msg']='红包已领完,你来晚了!';
5 I. c/ U* o& u - }5 e# P$ r6 \; _6 B, R5 C
- M()->execute('UNLOCK TABLES');5 [+ Z/ z& G( i: }; I8 G
- }5 p, f& p7 O3 a! X# o$ S) v
- }
) g. x9 x A, _ - }else{
v8 C% Y) v' e# D8 A - $data['msg']='非法操作!';% T+ K, q/ y$ ~* d0 _
- }3 p; s/ _; R4 E5 q- ^$ F
- }else{
* c& _; H- U# ]7 i5 d - $data['msg']='还没有到活动时间,请晚点再来哟!!';) J* v9 v1 z; a, k0 Z* r: m5 _0 ~ p& H( J
- }2 c9 ]; {+ I/ `0 E6 j( P2 @% n/ l
- } `7 t4 v; R0 {; ^3 q* {5 ?
- exit(json_encode($data));2 A/ J( B: u2 l" U$ ~9 R4 k2 R
- }
复制代码
6 |1 W; r- p* h9 t' U* ^# O) i: \0 u& ?& U: S* {
|