|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 6 _3 d0 L1 d4 [5 p
Mysql中的锁语法:+ w2 G" z' W( {( g& c8 X z
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】7 ]# e7 p. U% @6 v
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表2 ]: q& a* [; p6 r4 V
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
! \5 ?8 b b g' l% z- X注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :2 O+ v+ q4 H3 e5 g4 j
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。( z G2 k' @7 F! |
测试时,有个文件就行,叫什么名无所谓 总结:
+ f9 D9 p% O+ a7 }% p' O项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
: X; X) T% G' C1. 高并发下单时,减库存量时要加锁
# ^4 q8 a! W4 K( n2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*( \6 Y- G. p- B8 w8 w
- 模拟秒杀活动-- 商品100件1 g9 p- j7 P% ]# Y m
- CREATE TABLE ta. L3 y' I1 E) ~3 D
- (0 ]& I* R0 _9 Z( ]4 [" G
- id int comment '模拟100件活动商品的数量'
( b. A! D' U; s8 r - );
. R3 I7 n) g6 i; u - INSERT INTO ta VALUES(100);
: c1 i2 `1 L% S" @9 ]3 V7 Q E6 X - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
# N3 G7 ~$ Y/ ~ - */
' v8 y# t, D! Y u8 b - 6 c% }* H E5 A5 o4 o
- // 关闭错误报告
- d; o. D3 S* w! p, I( q - error_reporting(0);
' C. b6 W" |7 ?' X& t+ A1 S3 A. L! v - ! h9 W% s. f. f( a6 P2 C* r1 `( A
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
; [0 ]) @9 r2 m+ K# y - $dbuser = 'root'; // mysql用户名
3 d6 }+ H" u2 @ T+ m. C& g' J - $dbpass = 'root'; // mysql用户名密码
, u% D: k& r4 h0 N$ |: {! c+ r+ Y; ] - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
6 f' ~1 \+ `; o5 v/ y# ?. z0 k" k - if(! $conn )
1 o) a8 z3 t- y - {4 Y% O# n9 p9 K# y5 n0 p4 p' _" r
- die('连接失败: ' . mysqli_error($conn));9 d# D! o; t; A* F% y: d A- h; B2 ?
- }- v' ?3 s3 E% z3 K, l" |
- // 设置编码,防止中文乱码1 c0 x5 I# q' B: E; H* n
- mysqli_query($conn , "set names utf8");$ G9 t) o# H7 b; R; `* N' [
- mysqli_select_db( $conn, 'temp' );
( J2 s7 L1 \. J% F - 8 I% @3 b, r$ X) f
- # mysql 锁 4 q, {. G3 H. s1 I8 o4 v
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 " h9 ^# h- G- h) ?- K1 X
- $rs = mysqli_query($conn , 'SELECT id FROM a'); : j) ^8 A; e' A5 \- S, e
- $id = mysqli_result($rs, 0, 0); , k3 c( T' i( A
- if($id > 0)
, [& R4 i6 y* j4 x- S3 H R" u, i - { / C$ j/ T* a: ]+ y0 }
- --$id; 9 ?! p6 _/ S" z% Y3 v8 W6 L
- mysqli_query($conn , 'UPDATE a SET id='.$id);
, L1 B2 [& ?, O( z4 B - }
" V# f2 t2 T3 h$ W0 S$ v7 ^
, z; Z7 _, \6 G* D- # mysql 解锁 : k% f2 L9 L% y* g2 a
- mysqli_query($conn , 'UNLOCK TABLES');
( _1 j' A5 [/ U& }( ^ - //查询解锁后的id值; b7 k1 ?8 o" G# h7 Z
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
& V# e8 D6 H! ~ ^9 C+ u& q& a; G - // while($row = mysqli_fetch_assoc($res))( g" N/ h" T U" h! D/ A0 t
- // {& [6 [/ \# W; C' H
- // $id = $row['id'];2 E7 o# I+ |* ^6 Z6 Y
- // }) ~2 M j5 F8 a0 h- m
- // echo $id;
复制代码
0 [, P' u! O- N3 N, B2 H5 I z; c/ }& ?- @+ a; @
* H( y# C& x" H% RPHP文件锁示例: - /*
/ t* \3 x/ F* v8 T8 ~4 y$ I - 模拟秒杀活动-- 商品100件6 b& L* \0 ?: T- ~
- CREATE TABLE ta2 h5 c7 b) P i" O; M) G
- (* b: v4 r' U0 W& D; A: A' N
- id int comment '模拟100件活动商品的数量'
/ _/ Z7 Y8 v9 m ?- e - );
) Z" l W4 T: m3 ` - INSERT INTO ta VALUES(100);
* V6 a- @1 N' m+ C+ I( g - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件. y. {5 `. i0 R" g/ V A' [
- */ 0 c) w1 V( S# z2 ^% L; L2 q% _
-
: {1 S4 J7 O; A) n0 U - // 关闭错误报告( }9 c: C4 E+ P& ^# T: l
- error_reporting(0); + _2 A" T7 ]0 O3 n
4 e9 R* Y8 q8 r0 _- $dbhost = 'localhost:3306'; // mysql服务器主机地址6 d: c" q4 T0 C; a& J8 ^
- $dbuser = 'root'; // mysql用户名
- v; H7 u: F+ l - $dbpass = 'root'; // mysql用户名密码3 a' o+ |1 P' ?: ]
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);5 ] K9 d0 V" s- C% ]% P$ Y& P
- if(! $conn )
# w+ h; h( T1 ]( c+ v+ W8 W - {
: j& l; J g' k( [5 e% K, d9 | - die('连接失败: ' . mysqli_error($conn));
$ V. X3 W6 u5 Z9 m. |; u3 U" c - }
/ Z9 {9 Z$ m- }, {( D8 B9 b1 r7 d - // 设置编码,防止中文乱码
" f& G+ V: t _4 q - mysqli_query($conn , "set names utf8");
* g* R# |% g7 j% q/ o3 v" s - mysqli_select_db( $conn, 'temp' );
2 x! K& L! ^& n: `5 j: q5 n1 q
+ ^! N/ h4 z4 ]" x0 T+ \- # php中的文件锁 + G7 b! p" b3 i" p) }
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
; F/ b- E, b! S! ?& l: R2 O - flock($fp, LOCK_EX);// 排他锁
4 N$ ?7 t& s! X2 H; e; N - ) I" e& B- n/ Y1 T" j- u+ l" D8 V
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); $ `( x1 ^, f- }$ E$ s* @% O
- while($row = mysqli_fetch_assoc($retval))
- S. A% X: E( ^( d. [+ h, H$ ~& v - {
! x) f- G9 m, @: ]# y - $id = $row['id'];
+ e& d+ Z2 z3 H. s" |# b+ c. u - }
' @: g( @) \8 f6 U! \/ h. k k: | r -
/ [0 s/ W# K5 E; e2 E: h* i - if($id > 0)
; A* K" a3 U6 |% l; r - { - [, c0 G5 w6 t) R
- --$id;
8 z- z1 V# R0 ?4 ^6 \ - mysqli_query($conn ,'UPDATE ta SET id='.$id);
0 J& E N: R0 k: u, Z, J* p - }
t3 a9 }/ n0 \1 o7 b* ~/ g - # php的文件锁,释放锁 & l, w. m' R) I+ Q9 i7 o
- flock($fp, LOCK_UN);
9 Y" t0 c6 H+ Z; V% Q" d" d" u# t# @ - fclose($fp);% \- Y# C D# W& Z0 g" t) ~2 ^+ c
9 c& v1 R* P5 l- // $res = mysqli_query($conn , 'SELECT id FROM ta');
6 P: D. C" J4 ~$ ~, o - // while($row = mysqli_fetch_assoc($res))
9 \1 m1 F# M4 d$ v - // {
6 z9 }' ]$ E) X/ v6 f, Z8 z - // $id = $row['id'];* d+ W. f0 n3 C: N$ B- X
- // }' q/ F# Z2 Z. q* G, x5 h1 w i
- // echo $id;
复制代码 ) Z) D: d4 o; n7 E. p
& S- L# B& ]; S4 k% a
抢券活动实例: - public function envelopeSnatching(){
% P1 d$ V( x8 i) b6 P2 q3 p! g2 f - $lingqu = $_POST['type'];. w' {" ]! w4 n; U. t9 m% p
- $uid=session('u_id');//用户id4 A3 s. c5 ^& l1 F+ x
- if(!$uid){. p$ p; X3 }) r, |+ ]
- $data['msg']='您没登录,请先登录!';% X. ]2 Y9 C+ d8 w6 u6 i0 i
- }else if(date('Y-m-d') != '2017-12-12'){& i# d, X5 S" f- U' F% p1 g
- $data['msg']='不在活动时间内!';
/ d# n. K4 @3 x+ s - }else{
' Y' t9 ?6 V% c - $hours=date('H');//当前小时数1 E8 n; b. A" o
- if($hours > '09' || $hours > '17'){1 V: J* z$ R2 Y
- , P! M) Q5 _" S0 G7 F
- if($lingqu == 1 || $lingqu ==2){//点击10点的 C; i- V2 B. ?. [2 {
- if($lingqu == 1){7 [$ { b/ x2 D9 U" y0 H/ b, j
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过9 J6 j- d' D9 i
- if($hours > '09'){ l! p* W8 m/ o8 ^8 }+ s. B b) Z
- $num=mt_rand(25,28);//优惠券金额& m, E* {" H0 R, ^( S5 u
- $id=1;
8 _; D0 C8 T' H - }
; G0 @3 f0 C! m2 m0 c# e - }else if($lingqu == 2){
% H# z5 W5 c5 Q8 B) E - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
2 s8 t0 Y' M1 A7 N7 n- t - if($hours > '17'){3 i# M/ s; C. R5 } H
- $num=mt_rand(50,55);//优惠券金额) e, V% I, c8 Y; U
- $id=2;" I6 E6 P% `8 L9 j
- }8 v) ]6 s. k x6 G( r% s7 A5 S' n
- }/ U8 G0 h2 W6 H/ R7 R- K1 W
- if(!$id){! p* l+ w8 M1 c; |( R
- $data['msg']='时间还没到,晚点再来吧。';
5 W" L, M' {- z, q2 n - }else{$ }$ k3 f G3 ^2 U1 x
- if($is_lingqu){0 v5 m% L; S0 W& I" X
- $data['msg']='你已经领取过了,留点给别人吧!';
7 m7 P% }5 v" |7 z - }else{
$ P8 J* [. P/ P. l2 z: k - //锁表+ v9 B8 }9 C! }* w: d+ \2 i2 x7 a. [3 K
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');+ y& \+ B. Q" o: I! K
- $active=M('active_num')->where(array('id'=>$id))->find();/ b0 p9 q: f1 d- b# v6 b
- if($active > 0){0 ^1 [; u1 q K" h3 A9 O
- //开启事务
& X. t) [& a9 d5 w - M()->execute('start transaction');
0 A2 T. p; U% c - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));! M% Z2 u% x% h U% b" i& X
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
; \6 w0 Y- S# J( e; _" } - $members_preferential = M('members_preferential');
5 A' e( e. _, P7 z- r& { k - //对应投资金额,2 q, k2 l2 p9 |3 L- d( k) a" ~
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
% c5 l5 l8 M: x! v! |: i; { - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
2 U* ^% q6 v: H. z - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间: Q- n: b! H7 C3 A! L
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券/ [; w1 s1 Z$ E) m" K. f
- if($save && $add && $add2){5 L* R& D/ Q3 F. B) N0 s
- //事务提交
- s0 V5 H1 r$ R. G) L8 h7 i - M()->execute('commit');: L5 m" m( _0 m6 j
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
% Z3 A6 T. P# U7 G6 g1 A% k - }else{
% [" M0 M9 a6 u( h/ J - //回滚7 u: t/ M& \3 q p' y1 B
- M()->execute('rollback');. v0 K7 [8 w4 R0 w
- $data['msg']='未知错误!';
. m# W1 ]) I) U5 \& { - }" J( Z K6 E' H6 R+ Y, B M
- }else{
9 @0 T4 h' u& R - $data['msg']='红包已领完,你来晚了!'; S8 a1 A. y- S& c$ S. m9 Q
- }
1 x, H* W( x3 Z% Z8 ~! X& u - M()->execute('UNLOCK TABLES');
3 f2 @. r' ~' P7 X: Y, ~ - }
* I4 M: N; L, d( Y( K( ~- t5 a - }
# ~' W3 F9 x" [ - }else{
# U0 J! }- C9 Q$ d6 t - $data['msg']='非法操作!';/ s5 {9 Z* N ?# h7 W$ J
- }' p( u' `" o# ~/ |3 ~" G
- }else{
' D( F' r( w; }; j/ o7 W - $data['msg']='还没有到活动时间,请晚点再来哟!!';
0 w m0 g: \# F R7 q - }7 ]% e: z3 ~% w) M9 Y2 B9 `
- }
, n: I* Q# N/ o - exit(json_encode($data));
& W$ U2 d" `& L - }
复制代码 / S/ ^' e; I: B" ~+ C8 r7 a
2 j) a% l0 J! }! b% Z$ b |