模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
1 {5 u2 s* L5 V6 q4 e6 UMysql中的锁语法:
% X- l7 P' c- d& ~2 eLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
0 M$ J( d( K! ]( _% DUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
- `) m: c# t5 [" iWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
5 N- h1 f) ?' z2 M注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
b6 i1 c! f0 e9 o文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
4 ^; Q/ h R2 r4 K9 F测试时,有个文件就行,叫什么名无所谓 总结:4 ?8 Q: u1 f8 g+ v" C! |
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:& f/ n) b& T5 Y i- f$ j
1. 高并发下单时,减库存量时要加锁. e- |- k: p# s6 A4 P* m
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*9 ]# D3 `/ X1 ^: A
- 模拟秒杀活动-- 商品100件
! D/ s7 O; m1 y" X2 M, i- z - CREATE TABLE ta
2 b* |$ ^* D) S& o- k1 } - (2 R, T9 a, I: l6 Z% h
- id int comment '模拟100件活动商品的数量'
8 |2 k0 O" D: V) H7 y' ~5 Z& Y - );$ l& S y6 F4 S# g0 Q
- INSERT INTO ta VALUES(100);
# c% C, f1 ~! B# h4 _7 n6 N - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
- }" V: Q1 Y+ v: e- J - */
: h! G/ o% T2 S* l6 C& q! A/ u -
5 c/ c9 k6 U5 e- l! S - // 关闭错误报告+ l! x# Q# a9 O& m
- error_reporting(0); 5 ~) a( R7 q% W
- 2 z. C( z: I B: `
- $dbhost = 'localhost:3306'; // mysql服务器主机地址, Q' S/ ]. B: `
- $dbuser = 'root'; // mysql用户名3 `& P& v$ `" H5 G( b
- $dbpass = 'root'; // mysql用户名密码
( y8 @2 { b {: y - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
; q, Y8 q, A2 Y& ^ - if(! $conn )
/ U; n: O- a# {# [ - {2 V) t5 D+ o0 _7 K3 L/ \. S
- die('连接失败: ' . mysqli_error($conn));8 E1 V9 C+ c, p5 T" `
- }8 P8 F% H! y; F$ Y9 v B
- // 设置编码,防止中文乱码
w7 T- D( [: P - mysqli_query($conn , "set names utf8");4 Z# P. P- h ^6 ^& c: R- W
- mysqli_select_db( $conn, 'temp' );
; U3 e/ n+ m8 d' W; Z) m
. J* T: i/ Y1 I5 J0 U7 l [- # mysql 锁 2 b! D$ [4 B: n
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 5 }9 _( z3 \7 X J
- $rs = mysqli_query($conn , 'SELECT id FROM a');
4 x' C5 e2 e2 \- J, i - $id = mysqli_result($rs, 0, 0); ; ?! g4 {, l- `- v/ a- z$ X
- if($id > 0)
2 w2 w7 U& p( n0 J7 b2 r - {
/ n* C# T2 ~% O- E% C+ L) S0 U! Q9 x - --$id;
; u, ]9 {4 [' @0 w& z - mysqli_query($conn , 'UPDATE a SET id='.$id); 0 |, U9 \! Z' P6 b
- }
: F$ A* W* ^. k# X7 q* R6 ]" I3 G
4 o1 ]" Z! u; @, [# E- # mysql 解锁
: n( L$ ~1 a% M - mysqli_query($conn , 'UNLOCK TABLES');
: d. r" a" s! v, i: V; d7 E - //查询解锁后的id值1 _8 j) H# F2 d( s
- // $res = mysqli_query($conn , 'SELECT id FROM ta');$ U6 V9 o* C. s+ W
- // while($row = mysqli_fetch_assoc($res))
" B9 J c3 i1 T- U) Y* r$ S! { - // {) w+ L2 R0 ?$ C9 g2 _* F
- // $id = $row['id'];, E4 \. p# k; L7 a
- // }3 B b( j9 t* @ n. ]
- // echo $id;
复制代码 + U# S1 G6 o7 U
( t% \3 n) A9 V. h- Q
6 N2 `1 a4 [) j8 V3 TPHP文件锁示例: - /*
# X' A, M' c! S/ `. U8 W% M0 l4 s - 模拟秒杀活动-- 商品100件7 Z. f. v m7 g( q3 z8 h- |. a
- CREATE TABLE ta
' q7 s1 Q6 o0 ~6 D& [) E3 z" _ - (
4 `7 }2 u" W' g# H+ i( U- I - id int comment '模拟100件活动商品的数量'
8 y4 |5 }5 N5 K% r& M% M3 _" \ - );
$ V$ s( B- [2 y: K - INSERT INTO ta VALUES(100);
" w: A0 w+ ~2 C- g' k& m - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
1 b$ M6 {5 @( U9 r - */
% H" S- x' W5 n7 ?% f/ m8 @/ c. C - # }& Q, M3 {* O/ x; t
- // 关闭错误报告/ M) o1 H2 l* @2 c- H% G4 V0 P+ \/ M
- error_reporting(0);
! u4 l/ {' y( X$ d
) W9 } P. c. p$ [( c1 e* x$ x- V4 R; F- $dbhost = 'localhost:3306'; // mysql服务器主机地址2 `; s! v ~, F1 Z
- $dbuser = 'root'; // mysql用户名
4 G/ Z# U& S; o2 p - $dbpass = 'root'; // mysql用户名密码2 ]/ j) l1 w N# ?
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
+ f Z0 `7 U2 ^# h0 {) Q% R' U - if(! $conn )+ [, p5 Q. f( `, C
- {+ f3 R. R6 G: M. e
- die('连接失败: ' . mysqli_error($conn));6 t+ y: ~7 H$ K( \. c: o2 a
- }- O8 M# c B! m5 Y/ I8 n) I" G/ O
- // 设置编码,防止中文乱码* S4 n4 k/ e0 L9 D8 K0 r$ i, a3 ~# `
- mysqli_query($conn , "set names utf8");8 K. a8 y/ w+ G0 K: H
- mysqli_select_db( $conn, 'temp' );
! P5 X; K* s# b7 e; i# g
/ l6 J8 H# p. `% X' |7 D- # php中的文件锁 $ \$ V0 v; G8 R: a# i# ]& Y
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
* ^9 x' u. A6 v( j, h+ P% ] - flock($fp, LOCK_EX);// 排他锁
6 G% V# \0 H6 l5 n Y - " X0 L$ w( \6 O9 D4 K6 Z& T
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); ! p( Q8 E/ \2 [3 Q0 ^/ i3 U
- while($row = mysqli_fetch_assoc($retval))
/ A$ T" ?( s" Q' e$ n - {, Q+ q" x+ w# r5 s
- $id = $row['id'];
/ c2 X: ~1 D# H+ S, `2 N- f - }' V% w7 y% J' h4 w
- " w( z$ [9 v& T1 a& u; a
- if($id > 0) 8 b4 x! P) ~# R% F0 F' N L5 }- V
- { ( N: M& I2 `. B6 ?+ W( P0 ^
- --$id;
3 {' o# a9 k% L8 u3 `" \ - mysqli_query($conn ,'UPDATE ta SET id='.$id); " u6 U# R2 \+ b i
- } & y: U$ x6 c/ p. m2 z5 g0 F
- # php的文件锁,释放锁 6 l- V4 Y& ?( T: B9 r; H4 }( m3 c
- flock($fp, LOCK_UN);
: O2 ?; q. n5 C3 ~3 d! V - fclose($fp);( M: Y e# J. m- I7 L4 d* T$ V
- ! \; i! ]7 J9 q4 E
- // $res = mysqli_query($conn , 'SELECT id FROM ta');: H5 p1 w9 M. W8 s; K/ G' K
- // while($row = mysqli_fetch_assoc($res))
( w: t3 @- \5 b2 F( d' g3 h; } - // {
3 }" e; i+ C2 _5 q - // $id = $row['id'];3 u- a# ?# ^- w8 z" }
- // }6 a# p7 X9 X' O" H. `! X2 ]' f/ S
- // echo $id;
复制代码
1 N+ p1 i. A) X* J, Y! j$ W( U! w) Y5 o
抢券活动实例: - public function envelopeSnatching(){6 ~7 j2 t2 G9 G4 u8 @, I" D% b
- $lingqu = $_POST['type'];4 p5 L& `/ e+ A- Z8 I- w
- $uid=session('u_id');//用户id% |3 n2 ?$ [) _5 _- m+ {
- if(!$uid){8 e( X2 r) x5 Q/ I# v
- $data['msg']='您没登录,请先登录!';
# \$ B% C, i; s( M - }else if(date('Y-m-d') != '2017-12-12'){+ M3 i) w( A5 k
- $data['msg']='不在活动时间内!';
5 {3 I6 q3 K4 F0 h. G2 o3 ^( s - }else{. g f. b% X" D7 q
- $hours=date('H');//当前小时数$ a+ l, b' x% I* ^# f
- if($hours > '09' || $hours > '17'){
' t+ @' Y( |( t# o3 e( Y3 G
7 e( y1 Q( v. H0 A1 u( H/ _- if($lingqu == 1 || $lingqu ==2){//点击10点的$ r; i x4 S& J. ]' R3 C2 O
- if($lingqu == 1){
# ]3 @) X0 c: @$ Q+ ~ g+ d0 x5 t- g - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过9 h1 `2 Z& T! L8 k% X( o
- if($hours > '09'){, E d" `7 Q* w- r+ ^+ E/ {) ?
- $num=mt_rand(25,28);//优惠券金额
! g. P/ Q: b' Y% x, {8 k - $id=1;
0 u# ]3 m9 H# e. J9 ? - }
* L5 A% o; E7 b- ?! r/ L - }else if($lingqu == 2){: X5 \7 f$ U0 V; V1 M7 b
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();2 l4 q+ i) n9 `' Z
- if($hours > '17'){
" `% C. u. C+ K2 g - $num=mt_rand(50,55);//优惠券金额9 q) _2 f0 W9 P9 w4 V. T
- $id=2;2 s. P) _( u8 ?# | D. z& g
- }
5 H. v; \& R' U/ f7 }5 h: o - }( J- R: N( f. t- }3 R. b
- if(!$id){8 `2 g) D3 e3 I1 d
- $data['msg']='时间还没到,晚点再来吧。';3 h$ f: J7 N/ j* z: }6 R
- }else{5 V. d) u6 q3 N+ g( I
- if($is_lingqu){" d& p5 n; E2 n: `3 H
- $data['msg']='你已经领取过了,留点给别人吧!';3 x+ X/ }0 X4 v* \; w! d& N& S6 F
- }else{
f5 `; |* w2 G r - //锁表
& N2 m* m, @% T/ [: a) r" C3 E - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');" W6 [4 {0 C" ^( N# S" a- W8 e( s, o
- $active=M('active_num')->where(array('id'=>$id))->find();
- G4 V6 M& s; K. v - if($active > 0){
s* s4 g' d3 Q$ L. E( ]' a - //开启事务+ {% M8 C8 S9 ?. P
- M()->execute('start transaction');) H J$ ]5 D" ^- x. }
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
5 x; G X4 O8 Y+ m& |/ P/ Z4 J - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));# M% T! l: R7 s; {& p' Y6 M, h
- $members_preferential = M('members_preferential');! o, h# H$ }9 | J' a
- //对应投资金额,
5 p& x9 _; r, { T - $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));/ r4 ~% s( `, w
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');3 u- G# w$ m4 s6 q& a" {0 I
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
, S) F" N2 Z# n - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
& i( p, [: o' }1 p$ o% p - if($save && $add && $add2){
+ P5 T3 ~8 k l9 H; g, @0 }3 ] - //事务提交3 J9 \$ {% M0 W- t J! I5 H
- M()->execute('commit');. M# Z0 |( C' M
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
3 f7 d* y8 Y# R: d - }else{0 i' k' |0 i* ?, W
- //回滚
# E) F+ Z# o! o+ w+ w7 o) E - M()->execute('rollback');& I# C" |- J s: g! _! J+ i
- $data['msg']='未知错误!';
2 e/ K* w1 x# d3 | e - }
) Y! w$ `( }2 ]' b2 D7 Q7 S4 x - }else{
. d5 c3 S! E/ N# H7 w2 O4 A" u5 J) Y - $data['msg']='红包已领完,你来晚了!';
7 \5 P) f7 _( u8 K. p - }
: q+ D2 E& W$ X' x - M()->execute('UNLOCK TABLES');5 D/ |# ?, p0 a( r2 O
- }& I) j. a0 I: ?+ e
- }& p: q4 q. t/ ?+ d% h$ C, I
- }else{% H* J8 ?$ h( l: V
- $data['msg']='非法操作!';
. k$ m! ^, P; I7 e0 M; W - }1 j. o( }/ \7 v5 K) G; u/ E
- }else{
% g% }' ]# b9 m- Z8 t2 x8 @/ ? - $data['msg']='还没有到活动时间,请晚点再来哟!!';: N" {1 R& t3 t, s9 G4 ]. }/ e
- }
% @, ]6 f1 M- x' ?: A - }; W Q& P! ]) f0 H) {, {
- exit(json_encode($data));
- r, V# t# Y: w - }
复制代码
, x& m' U- i0 U* M) @+ w& b! k2 W2 @
|