|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
- L: ~. o6 ]5 u" u: a# jMysql中的锁语法:
5 H$ p; X; V8 x& W" h& oLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】# V) K+ x* k5 s+ t7 @8 C% U5 ^) ^
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
3 @ M6 M! A! E* _Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞5 T! B* t, B1 c) n( X5 |8 P& X$ E
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :( D$ n; J1 j5 w2 V' y
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
7 v% \2 C' q: i6 f测试时,有个文件就行,叫什么名无所谓 总结:
" J2 |) O) |- A) u% s O2 p2 h项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:" |+ P/ r5 V5 [
1. 高并发下单时,减库存量时要加锁
/ I. O6 V3 I& D' r' y+ D2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
. L7 ^; V4 f2 ?/ d3 n4 \) g. C9 E - 模拟秒杀活动-- 商品100件; v6 [1 ]0 m. y# A& F: O g
- CREATE TABLE ta8 y) O3 X3 [/ n( m% b: t
- (
7 O) T) w" p7 j/ d) ^2 A- C - id int comment '模拟100件活动商品的数量'! K8 r- j9 ]8 F; z
- );! ?/ l. M6 c& J `) Y5 ^0 P
- INSERT INTO ta VALUES(100);) h. d' `$ E4 B C' u- d
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件: f' i8 w; a1 L
- */ 3 D. d% O8 h( o, l% F
-
& D( V. r/ i' T3 {6 q5 f - // 关闭错误报告, v6 C: y9 s' f1 g1 ?
- error_reporting(0);
" J4 X, T3 p& ?9 R
8 P0 V6 E. D% V; K" D ^- $dbhost = 'localhost:3306'; // mysql服务器主机地址
: A0 F8 L& f9 X+ ?( }! ^1 z - $dbuser = 'root'; // mysql用户名
" N k0 y# [2 \ - $dbpass = 'root'; // mysql用户名密码
3 r% t+ e4 y) B; A5 e - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
, q8 }0 E+ ?& o$ L: ]6 A - if(! $conn )
$ T! R) ?2 W; E6 p7 V- s/ [6 N - {! C4 f7 D4 a( P/ U
- die('连接失败: ' . mysqli_error($conn));
. V, v5 P; c, W# x1 o1 } - }
4 a$ K& Y5 I4 x6 `, R2 i: a" ~ - // 设置编码,防止中文乱码
& V8 @" j; k/ V7 w+ e - mysqli_query($conn , "set names utf8");
" n) y9 Q9 m- H! i) x$ ~& k8 u* B - mysqli_select_db( $conn, 'temp' );
( e7 {% c4 H! v1 N2 K' j( n0 H) O - 7 v5 u1 G1 F! q8 G9 x5 p
- # mysql 锁
9 _3 N: @4 Y1 r0 K! }5 s. { - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 1 c O2 _) y# ^
- $rs = mysqli_query($conn , 'SELECT id FROM a'); @. j. v, f3 ^" z+ N. L
- $id = mysqli_result($rs, 0, 0);
' w' n$ A( f$ c+ h9 y( O- I8 t# ~) c8 {" I - if($id > 0)
3 C9 ^3 L0 [- z% {4 z7 w: A - { 8 g3 h' r2 H& |2 B! y& G% Y
- --$id; # ~% }) V i3 E$ E
- mysqli_query($conn , 'UPDATE a SET id='.$id); / {( ?6 ?! x% [" L
- } 7 w4 o* `3 x* y7 U" c- r
/ k) z# V( a' H- # mysql 解锁 4 G, o6 G3 e$ Q' m' ~' v
- mysqli_query($conn , 'UNLOCK TABLES');
' g0 A. x. U2 v% K) ?4 N- v0 y0 ` - //查询解锁后的id值1 S/ o# `# n6 l9 a+ x8 B7 B4 ^
- // $res = mysqli_query($conn , 'SELECT id FROM ta');/ Q! d8 O1 n6 F9 Z. t
- // while($row = mysqli_fetch_assoc($res))0 C; v1 ^/ S; |, S
- // {
# Q% S+ x: T. U' I - // $id = $row['id'];
) K0 N; i# j! R+ v3 Y/ |9 ]3 ? - // }
( `2 B% j8 ^7 K' X - // echo $id;
复制代码 ; g9 P- o. N& G5 ], U% q: e
; Y! w1 s" U/ W7 ~0 j' C
+ C/ q+ R( @1 \. t# x. I& n3 B. hPHP文件锁示例: - /*
! K3 N) q8 Z+ x% b: `8 b7 d - 模拟秒杀活动-- 商品100件8 H, h+ L& a- `9 {7 v4 F
- CREATE TABLE ta3 |7 \# f6 w$ d
- (- J; J& U2 U& g( v
- id int comment '模拟100件活动商品的数量'9 a& \4 N) L0 r3 M2 _6 O. n
- );
4 X7 b" v9 ?' {' r6 W- f - INSERT INTO ta VALUES(100);% J- r* c! h/ i# k5 J1 B, t
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件; E+ B8 d, h4 s3 a- L& I1 q
- */
1 }! R; L5 ^* [ - ( G! c' y j# J& B
- // 关闭错误报告
5 Y" H& o# v! T9 M0 B - error_reporting(0);
. y* A9 k) e9 _3 q8 [ - 8 `% n5 ?" H: ?+ N, \" ]9 B
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
8 y) Y* i4 B4 W2 d/ I - $dbuser = 'root'; // mysql用户名/ o4 a$ S2 ^8 U: |& n5 K3 T
- $dbpass = 'root'; // mysql用户名密码; W" S+ s5 T& `3 w4 {9 W3 s# U# j" \
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);8 v: `. h( v1 r6 t! u
- if(! $conn )7 U# J4 P5 J9 Z& q+ L9 K
- {; ^# Y8 b: E6 t0 M0 c
- die('连接失败: ' . mysqli_error($conn));+ ~( H( d$ p0 w, ]+ ?
- } m( B- [ P# Q( _0 Q
- // 设置编码,防止中文乱码
' R" O# k4 a5 \8 S& o - mysqli_query($conn , "set names utf8");
( w* v& m$ D$ X$ O e1 ]" f - mysqli_select_db( $conn, 'temp' ); - k0 Y* l7 t% i9 M! L
: _& A% q3 [" C- E% f- # php中的文件锁 4 L: A$ u0 y: p |: d) D" L
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 : p( o# W3 [$ i" f% K/ K+ l) l5 n% S+ o
- flock($fp, LOCK_EX);// 排他锁 " t: ]1 a& Q4 r3 t& b
' Q, ` V2 |. M& I" t: L- $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' K; @. Z% u5 u' S
- while($row = mysqli_fetch_assoc($retval))- T: u. i( F. O0 M/ e% z
- {
& `& _2 E* T& f' Y {3 l - $id = $row['id'];
8 v: Q# T9 l1 c - }
3 ]% c( G$ P1 c# d4 v -
9 n0 Y0 i6 c, ?6 W, E% B - if($id > 0)
* [' Q9 z o h% V: l - { + y8 a5 U7 k, ~) j: S$ r) }& j
- --$id;
/ V# y# [4 Y' ` - mysqli_query($conn ,'UPDATE ta SET id='.$id);
* x" g5 @$ F) q. N' T6 U, t - } 1 y0 Z1 C k; {/ p1 H% w, |, k
- # php的文件锁,释放锁
# U5 p& v8 @6 r9 o5 M( a% P - flock($fp, LOCK_UN);
* X, W, G, s) ]% V; y4 z& A) z - fclose($fp);
) N$ [! r% ^) m a - , n) A+ P- {$ k$ B( ^6 |+ P
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
! l0 b6 S" \1 U- u/ e( t2 p5 u - // while($row = mysqli_fetch_assoc($res))4 ]# e8 M7 G6 F: r4 Y
- // {
+ Y( [; @4 E& e* G6 t - // $id = $row['id'];/ _! Z! p) D, @- n- g$ Q
- // }
. j: `% A# f! M - // echo $id;
复制代码 2 _( _) z, j2 O: u
0 U+ d; D% {* S& g) M7 j
抢券活动实例: - public function envelopeSnatching(){$ d5 k: a: n8 v# ?# X0 U' w( y7 K
- $lingqu = $_POST['type'];
& l2 T) f2 ]' I3 Z! L - $uid=session('u_id');//用户id* R& y: ?, z& f: Q8 \
- if(!$uid){
! p+ Z6 a; p. ]& R+ [ - $data['msg']='您没登录,请先登录!';
- K: I- {8 I, e, i* w/ K - }else if(date('Y-m-d') != '2017-12-12'){8 v6 D' S3 ^7 F3 e
- $data['msg']='不在活动时间内!';* ~( d; f4 k' ?( V. V
- }else{. i5 T5 m% _1 E' k" w
- $hours=date('H');//当前小时数2 r5 e4 Z# i v2 u. N
- if($hours > '09' || $hours > '17'){
7 y% ?' q3 l/ m
6 \" }) j; {" r, B% J* \+ Z- if($lingqu == 1 || $lingqu ==2){//点击10点的
8 [ u* `! T: e* V) [! j4 a% L2 t - if($lingqu == 1){* R. I4 f8 V* I, J$ L0 O% a. o) V: f
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过% p" m. Y! F5 S# n
- if($hours > '09'){
, J' h `0 C" |) j: e) k - $num=mt_rand(25,28);//优惠券金额
' T* C' z+ N6 ] - $id=1;+ ~* {. w1 E4 n' w/ R
- }/ g0 Q( [- ?9 @
- }else if($lingqu == 2){2 {( V8 k0 P b0 H3 B! c- C, |0 R1 B
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
9 M; z! G: O4 r o - if($hours > '17'){3 t( d3 v7 i$ c
- $num=mt_rand(50,55);//优惠券金额
& G# S" G. X/ t: H( H* s - $id=2;1 F; _& v5 Z, s% e0 u
- }* d+ `5 c& u2 L
- }
$ _6 Z+ g, m; w2 N - if(!$id){
% ^9 Y2 |' f& f6 f& N$ M" |" V | - $data['msg']='时间还没到,晚点再来吧。';/ { t4 [8 t& ]0 _
- }else{
/ A) Q g ~) ` - if($is_lingqu){. A% O, {& V3 t7 u0 R0 Y2 Q
- $data['msg']='你已经领取过了,留点给别人吧!';7 o) r4 G1 A# R* ]' @" e& p7 p
- }else{
' }( u) A' t9 R0 \* x4 A - //锁表( ~3 b2 m8 x7 x7 f$ C1 P- g, N6 Q
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
% q6 z) F- f+ W# x% k0 y+ t - $active=M('active_num')->where(array('id'=>$id))->find();# s2 x% Z9 G j) n, }' \
- if($active > 0){" O3 R: o a8 k* r
- //开启事务# v; h/ }8 l3 ]2 x
- M()->execute('start transaction'); M& \9 Z' o2 s! e8 b. I+ ^# o; [
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
! P) y# u; S0 M# } - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));5 B! i* U: M [3 p. [( u# s
- $members_preferential = M('members_preferential');
/ W" b# v' d: s - //对应投资金额,4 _: u5 u- a0 m: Y" a C% d
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));( k; c3 E0 s: e- k
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');/ @9 j5 P% b3 Z) O3 o
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间7 h x" n5 _$ g- a4 Z" }
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券+ P% |7 ?( e2 E6 d' E/ S% ]
- if($save && $add && $add2){+ ~* Y; i* J3 ]; R Z! }- k
- //事务提交
* Q' @$ L/ |# H4 @7 U( N - M()->execute('commit');: H! }3 h3 M( T7 A4 c& Y& R3 i
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
' N( W5 H0 `+ g% r - }else{
4 ?& P8 w8 Y6 Z5 E$ l4 E/ M - //回滚
2 ?8 v! l: E. a `5 b - M()->execute('rollback');. y4 d9 H( i7 L( Y
- $data['msg']='未知错误!';( `* D4 |' h; [' l% X1 z
- }
$ O0 o6 ^# T5 Y - }else{! g9 n4 Q9 {3 `6 Q% q5 m
- $data['msg']='红包已领完,你来晚了!';6 p7 b$ [' B( k
- }
, M# p; N! T. N. \8 { - M()->execute('UNLOCK TABLES');2 ~1 o5 W3 {+ @& l( m/ Y/ H. [0 [
- }5 r. y6 Q( g. ?+ f$ X& k& U( J& T
- }8 q3 W6 e5 j h
- }else{3 Y6 f) f0 `: N1 J5 _ {: w
- $data['msg']='非法操作!';1 ?" F% E( Y; |( s- m* e8 H% K# Q
- }' J j# @% n# T
- }else{
u$ c+ l, @. ?' i3 o% R - $data['msg']='还没有到活动时间,请晚点再来哟!!';
8 @/ h% L4 K* ]$ ? - }/ w2 d5 Q2 {3 E# K# T9 Z" ^: B
- }
: p1 T5 Q( `/ [2 g; O* I [ - exit(json_encode($data));7 ]3 k% q- {- e0 M$ x3 A$ B6 S' Y% R
- }
复制代码
0 V2 C" b& {, o& q- X! E1 Y m: u& B$ y" ~) J" J4 n' [
|