|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 : W; i3 i, ^' D2 {
Mysql中的锁语法:
[" X; e) E7 O8 m& y- c u) h4 VLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】1 G' m, X0 k( O6 z( s R8 }- l
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表. e: a& }; O* x; h1 K
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞6 j; |& E. d) Z+ `
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
" J- B0 `" j+ O0 T5 M3 a文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。) q: L5 Y( _3 s, \
测试时,有个文件就行,叫什么名无所谓 总结:
- u) S& g- L' }% v项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景: _& H/ `. S6 l: f3 i3 }
1. 高并发下单时,减库存量时要加锁
# |6 R' J5 \1 n/ Q3 K% P. v* J2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*9 F7 r; ]. t# r% w6 _4 b) C
- 模拟秒杀活动-- 商品100件
9 ~4 e" ^( S( j4 c - CREATE TABLE ta
4 {0 n3 O/ E+ u* ]* O0 B2 M" ^5 \ - (" K3 G% R* O9 R9 n+ L' }0 {' j% m
- id int comment '模拟100件活动商品的数量'
1 t7 A# ?* w W: r+ D0 G5 r/ T - );
3 v# }. x6 K" x7 y3 Q - INSERT INTO ta VALUES(100);% w6 W( t' Y6 x9 S0 W5 U6 _
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件+ f0 P4 y4 Y2 p2 o6 F
- */
8 W1 F s/ }' F* L2 S -
$ Q3 n' z; Y' l - // 关闭错误报告( a2 c1 c5 V- j7 M
- error_reporting(0);
- A7 g( I/ U, A3 l0 A2 H' O4 A
% `2 M1 O. e5 i }, U7 m! P- $dbhost = 'localhost:3306'; // mysql服务器主机地址
- }& h8 e/ y$ q. N - $dbuser = 'root'; // mysql用户名1 k- f h: s8 B0 e& O$ i
- $dbpass = 'root'; // mysql用户名密码
% P& X1 |# W1 U* { - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);6 k3 \# S" ]3 W @3 `" r
- if(! $conn )
2 p( V" s9 p7 `( k - {
o9 C! a1 k& E2 C8 A- B - die('连接失败: ' . mysqli_error($conn));
. I+ F; X0 Y# N$ Q - }1 z. a5 X# i; I8 r
- // 设置编码,防止中文乱码/ z" O+ j# e: M% N6 D4 w
- mysqli_query($conn , "set names utf8");
( x) y6 E$ Y) g7 H6 V: ^! p - mysqli_select_db( $conn, 'temp' );
- Q, A2 N v( j) M - $ ], V' x! [4 d$ M8 _& O- j, ~
- # mysql 锁 7 k3 l+ E/ \# T: I* e4 N' w6 r
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 : a& I4 i) f' W9 ^9 U
- $rs = mysqli_query($conn , 'SELECT id FROM a'); ' k& q7 Q( ], V1 Z
- $id = mysqli_result($rs, 0, 0);
p8 E3 ~2 w- S. ] - if($id > 0) / Q' [, C7 g- y: N" t+ H
- {
' r1 C: \2 [) B- X - --$id; 2 `. S- ]1 _( n. P' p: P# |
- mysqli_query($conn , 'UPDATE a SET id='.$id); 9 i9 R1 b: L8 h# [7 Z$ l; O- ^
- } # Y6 f% z) i* H- K
- # i3 p x; m! j; O
- # mysql 解锁
1 U( B# }* D4 z0 z - mysqli_query($conn , 'UNLOCK TABLES');
: g! B" j6 t9 Y3 j- m! Q - //查询解锁后的id值
6 h# n/ p- T. h/ j/ U5 r/ S7 s6 M2 A - // $res = mysqli_query($conn , 'SELECT id FROM ta');
1 j6 z8 q, |9 A" J - // while($row = mysqli_fetch_assoc($res)), | C W' ]5 q8 M! z% W( G
- // {6 g# V: {. L+ M g3 P
- // $id = $row['id'];$ Z, c' _$ \' I' g9 n2 l
- // }! H' K# O7 J9 p, _! v2 C7 u3 |2 t
- // echo $id;
复制代码 ) j$ ~3 O! E( ~- F
; ~: V* i8 R9 X# H; w2 C
, ?% ?8 v% f1 d' [$ Y
PHP文件锁示例: - /*6 A! b% L$ X* j
- 模拟秒杀活动-- 商品100件6 |9 ^8 _2 {; o/ B
- CREATE TABLE ta o0 ` m. A' Q. m+ n0 A5 \' n
- (
X* y- ?0 l( t4 R& }: g4 e; f- U. f - id int comment '模拟100件活动商品的数量'0 c, ^4 Q9 d- A: C3 j3 H
- );
' t! E8 r. |2 u3 T, v - INSERT INTO ta VALUES(100);0 ^9 J7 Z, q4 ~4 b" N, z' l0 C
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件4 K7 U! j% z* I% o% P3 P# c
- */ " N: a; g0 G5 v! p! V
-
+ S$ S! s. ]7 [- E7 v B( }4 K - // 关闭错误报告
- B0 }" Q# k; m8 {9 }: k' k - error_reporting(0); \) a0 L; V7 }2 a4 L0 d
/ x& c6 [! N+ R- $dbhost = 'localhost:3306'; // mysql服务器主机地址
0 p$ A4 L, _- ^ - $dbuser = 'root'; // mysql用户名
# B' q- o) c8 z* Q' { - $dbpass = 'root'; // mysql用户名密码
2 X' t+ o2 c# j0 i - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
* r" p( c* G6 t' J6 C9 k% W5 w% \ - if(! $conn )
0 d- u. ]; l: D" B. ` - {
9 c( Y V; [+ t9 h* v - die('连接失败: ' . mysqli_error($conn));
1 s% q, @ `8 X& l! p: V - }
$ u. Z3 A9 S3 \) @' v& Q+ g4 q - // 设置编码,防止中文乱码
# Y! L7 \' |# }! e# U3 H - mysqli_query($conn , "set names utf8");2 f! g5 q: m' w& }" U% ]# t8 m( |, K
- mysqli_select_db( $conn, 'temp' ); ! g/ N9 `3 L) q$ E
- ' C/ S- o6 _: u$ ~9 P/ G8 W
- # php中的文件锁
8 I) v( f% Z2 e5 P - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
v% L" ^% x0 i; d. F$ v7 D7 G2 M - flock($fp, LOCK_EX);// 排他锁
, f- B, E' o5 r - . d! e- f: J' z- O
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
% Y) b9 n6 m: Q, V% B9 j/ S - while($row = mysqli_fetch_assoc($retval)); T1 b( ^6 ^5 k5 N) _
- {. B# J5 |7 X. z! h! y) K3 _8 B9 n
- $id = $row['id'];
* }* N0 I) B2 b! d& l; x - }
, Y* L2 @+ J: E+ b3 Z - ; m! L7 y" I4 Z- }3 K
- if($id > 0)
" D$ s" i7 @! L; m1 [. w# j - {
* \# V: h8 f. Z4 K& a) q" l4 i% P - --$id; + Z; D9 ?# C# d
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
3 ^' n: ^5 V+ ^! ~5 D9 K7 e - } 7 X5 t2 u9 E) ^% }0 @/ t; l
- # php的文件锁,释放锁
7 v* G( a/ |! A h4 ]- j( a - flock($fp, LOCK_UN); 1 c m+ P+ V$ R9 m; i. B: M
- fclose($fp);+ [/ Y( P ]4 @' ]" Q' q, ?
7 d4 P" s& k/ _' s- // $res = mysqli_query($conn , 'SELECT id FROM ta');$ H' x" C0 f8 P4 i* v7 O5 W
- // while($row = mysqli_fetch_assoc($res))6 g, h0 z/ S7 C& ]# _0 v0 f
- // {
2 \9 {& ^6 R5 J' y$ K0 F) { - // $id = $row['id'];) ^( u# B0 S# E% c1 e, u- [
- // }# h+ {" K1 c* v! G: @$ m
- // echo $id;
复制代码
" ~5 ^5 \# E1 q% g0 X, ^5 w6 x7 W! q) b9 w$ W- [* x! U9 _1 j& [6 ^
抢券活动实例: - public function envelopeSnatching(){2 h$ H2 a( M2 d- o8 [( [' N% w
- $lingqu = $_POST['type'];
8 h& y# b% z0 n5 w0 z7 c - $uid=session('u_id');//用户id
- R* y3 q4 f4 }) C4 p$ c! n - if(!$uid){
/ t9 p1 C+ |+ w: ?3 f# i - $data['msg']='您没登录,请先登录!';
) }/ Z1 t, F3 g6 C+ U! A& o% Q4 }7 w. L - }else if(date('Y-m-d') != '2017-12-12'){/ M. B1 M4 a" B8 [* t9 @2 @
- $data['msg']='不在活动时间内!';* f1 H e7 C) L
- }else{0 s, _4 G9 v3 v8 u4 a; b
- $hours=date('H');//当前小时数
7 b! e/ v# C: r- p/ s q - if($hours > '09' || $hours > '17'){
' u! K9 M, H" L. H0 C% \
+ J! W$ _: K" ~: n9 n3 h0 x- if($lingqu == 1 || $lingqu ==2){//点击10点的
6 n3 m+ o% {! ~; B - if($lingqu == 1){
% ~7 C4 ~/ \- s: m4 @ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
6 ]5 O& a( W/ f; v2 `4 m - if($hours > '09'){4 t, \/ w& l2 _& j2 k5 v
- $num=mt_rand(25,28);//优惠券金额; m: a V; r& g6 p
- $id=1;
! [3 w1 l! e, r0 x - }
8 ?' o& n7 `" b6 u" g7 G, v0 D1 d0 H - }else if($lingqu == 2){
9 a! G1 C% ^7 F/ Q: w, r& G" X - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
; i* ` ^# k$ W3 Y7 z - if($hours > '17'){' r1 c3 E. z; u1 I, r
- $num=mt_rand(50,55);//优惠券金额
4 s4 m8 s1 D, U' G - $id=2;
( e V& l0 [' P _" l0 u; [4 T$ \ - }
6 P2 [; N) Z9 z" n. B8 d4 D. S - }
0 g0 B7 J' Y8 ?2 \: [, K - if(!$id){5 ^4 d* k# H( U" t8 A1 ~ G
- $data['msg']='时间还没到,晚点再来吧。';4 i$ P7 _0 V* T. P4 u
- }else{1 o9 Y! d( L3 ]' G' ^
- if($is_lingqu){1 ^2 d" b2 ?, @7 w1 M& d
- $data['msg']='你已经领取过了,留点给别人吧!';3 y. O: S! X' ]; `( q" |$ q* r
- }else{
' T0 w) s* [6 i6 @! m0 x. c) t& T - //锁表/ @; r! B" S9 B% w& S/ S9 E0 z
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
2 j; d. ?. t. }2 i' C - $active=M('active_num')->where(array('id'=>$id))->find();
, n$ A# |2 h' }0 D$ b; m - if($active > 0){
9 D5 d) `, p. I# x) l4 C: s - //开启事务
$ F# J" T$ ?8 J6 J: A! Z! K, Q - M()->execute('start transaction');
3 f/ l- d, p+ |! G0 q - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));2 F2 r- f1 n1 M* }, N' n' T
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
9 M2 d3 Q) `- ~$ n; C - $members_preferential = M('members_preferential');- q+ ^% n3 q$ k$ j/ O. i4 y( E
- //对应投资金额,
8 r0 C7 i8 U+ d9 X' \, y - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));: M" u3 |$ j7 Z) I5 }. Q, v
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
8 W! W8 V! B p: {7 f8 F2 R - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间+ N' R; Y1 t& U- v+ a
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券( s0 L1 `. E- ~4 H3 d
- if($save && $add && $add2){' \% T. r" j) H7 t7 n& s6 e& L
- //事务提交; q% @! x3 Q& a5 Z G$ W6 o
- M()->execute('commit');
6 _* c6 J" i7 s/ T# Y! D) Y9 N2 X5 x - $data['msg']='恭喜你领取了'.$num.'元优惠券';& M) E6 n9 R# u- q+ u' _
- }else{
' D" v/ v& ~- W$ A - //回滚
" ]; h) L1 P1 M+ p - M()->execute('rollback');* g L5 w0 X7 z Q
- $data['msg']='未知错误!';
3 [5 D% I, r, _( R- m* N! C - }
5 X+ S; Q3 r: r H1 I - }else{" @& O! C4 `. d6 B Y7 k- d* o( `
- $data['msg']='红包已领完,你来晚了!';, _- U4 f+ `" i6 H; L
- }
, V. N) ?9 u U8 d( s, v - M()->execute('UNLOCK TABLES');
& X9 }: |5 P4 f! B) } - }
8 D+ _8 w7 m& ]) Y) b5 R - }! j, Z5 [2 q: S
- }else{8 s. {& r7 Z1 x' I- X* a6 b' V$ P
- $data['msg']='非法操作!';: D4 M" Y4 R/ s2 @9 }
- }
1 z, n, o. X$ T* G$ @; T - }else{$ J6 \5 ?/ ?$ n
- $data['msg']='还没有到活动时间,请晚点再来哟!!';
. y& h Y9 R/ y+ i - }
* v6 |( l0 u; @' L - }7 e: i R0 F5 L
- exit(json_encode($data));# l, c' b2 S7 \+ {! a4 F
- }
复制代码 / `+ b. n- e; ]" A$ |& x
, g! `! Z( J! ~8 F/ x9 r+ P1 a& o% f& `
|