|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
7 |/ X. `) r% u3 s8 ]: G0 e! qMysql中的锁语法:
b7 @5 ~4 M4 L: z) BLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
, ?+ {/ q( s- }UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表. d' e' F( ~7 h
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
& B4 \; I( M3 ~- n注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
6 X$ }8 L7 i0 i3 s) O# N3 h/ M文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
6 u. o+ z! T2 Z# l测试时,有个文件就行,叫什么名无所谓 总结:( F1 D% F& z7 g1 C- D: L3 ]6 \
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
" q6 |0 N6 S1 L/ k; g$ A1. 高并发下单时,减库存量时要加锁; ^* x. y9 D7 }' ?
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
" e! Q/ B, P9 A - 模拟秒杀活动-- 商品100件8 j& c9 U3 s* l( ]0 y
- CREATE TABLE ta
; Z, C6 S2 ]* X! M - (
+ B; q! c# _# e y3 O2 e - id int comment '模拟100件活动商品的数量'
2 g5 l9 [: F) l/ X - );
0 }, w) V2 J' r. W; ?8 e3 d - INSERT INTO ta VALUES(100);
! Y/ G! f& X5 {9 }1 X4 [ - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
# W& Q; |+ _ G4 F% P - */ # n% `: i, `9 A! i \" f9 b" g
-
! B! E3 n8 n0 O" t5 Q - // 关闭错误报告; k" e) Y6 i9 F8 k0 ?
- error_reporting(0);
, Y2 U) U+ U0 ]5 v3 y$ U - / N8 g% S: S! ^/ r0 j
- $dbhost = 'localhost:3306'; // mysql服务器主机地址* E/ J7 J, i; B x X
- $dbuser = 'root'; // mysql用户名8 Y: c6 x& _8 }& \( p4 m
- $dbpass = 'root'; // mysql用户名密码9 {- C: i4 J, c2 i* m! V4 }$ Q4 E
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
0 A S* }& Q( i - if(! $conn )0 [7 k, T0 h8 O7 d1 B& l
- {
6 L7 Z/ H7 p R' U7 z2 z - die('连接失败: ' . mysqli_error($conn));
/ n: x' B5 O' J C) x - }
5 i9 X. p: q7 j" H Z - // 设置编码,防止中文乱码
% q0 F9 U6 n0 X$ r6 @; ^8 e* s - mysqli_query($conn , "set names utf8");: F. H0 O0 T* n0 o' i* u* X4 N
- mysqli_select_db( $conn, 'temp' ); ( Q8 F- ~% K' S" m) f W
. d( L" x% U) B: m: G- # mysql 锁 - r2 w U' Z2 }
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 6 ~! j, d* t( ^9 v4 |
- $rs = mysqli_query($conn , 'SELECT id FROM a');
+ t; u& p2 `5 i8 @1 G) K7 m - $id = mysqli_result($rs, 0, 0); & }" s* l* T- T% p
- if($id > 0) 0 g2 T0 q# }+ J4 B% h1 U
- { / D; R, \, y. w1 z9 n
- --$id;
# a: v# t, f8 _% c - mysqli_query($conn , 'UPDATE a SET id='.$id); + i- E+ R" c$ ~9 W$ |2 D
- }
. W0 W2 _. ]2 l% _ - 2 W& a8 {, |5 b+ }" w- @- O* ?# v5 k
- # mysql 解锁 6 w9 I8 _5 d5 D8 j) V7 Y
- mysqli_query($conn , 'UNLOCK TABLES');
" E u7 i9 |* _4 d3 ^+ W - //查询解锁后的id值7 q4 e8 |& i2 I. E- f+ X
- // $res = mysqli_query($conn , 'SELECT id FROM ta');) x# S1 c1 N) ^9 ~
- // while($row = mysqli_fetch_assoc($res))6 X8 N1 M- n, A5 m& z- n/ z) f
- // {, A" }* M5 T0 X0 w: n8 Q9 M: d
- // $id = $row['id'];
6 x O6 G* A+ C4 [ - // }0 _6 g& ^# w4 N0 L& k7 s5 {- F8 T- t
- // echo $id;
复制代码
0 [$ [4 V+ ?6 q
1 X, h0 y9 H; n5 O; f
7 t: e0 M+ U+ q3 p' O6 J7 `PHP文件锁示例: - /*
7 c% j9 v4 A& M; X, r3 X1 } - 模拟秒杀活动-- 商品100件) J- l+ r9 w1 U/ Z7 Y
- CREATE TABLE ta
. `$ l9 T. l7 D, w - (: X9 W8 \. G5 E9 R5 v" r! W
- id int comment '模拟100件活动商品的数量'
3 K- O9 C9 c4 c - );
5 Z. z+ A, T% s: n( j1 W; J" H7 s4 ^% ^ - INSERT INTO ta VALUES(100);# d( K# d( `8 \9 ^9 U6 ?
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
$ T3 b" G: f& j% B& J - */ 1 ^3 P( H [* e: ^' v+ C
- 4 w+ _+ {3 S8 A3 a; e
- // 关闭错误报告
+ E9 X1 _/ V6 P8 E# [- {* s5 K. ?1 i - error_reporting(0); 3 `8 L3 m0 @2 j
5 _8 Z4 w! D6 {$ ?4 I& E- $dbhost = 'localhost:3306'; // mysql服务器主机地址! H9 R. j/ e1 {3 t; l9 l4 n
- $dbuser = 'root'; // mysql用户名( }: ^. G# p; m/ z s* I
- $dbpass = 'root'; // mysql用户名密码
& J0 V8 [4 _7 e4 A2 [ - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);" T4 c7 Q* [8 x4 o/ r1 {3 Y
- if(! $conn )3 l0 Z) _0 c: C' [. d' d6 m. a
- {
( }( C5 i, w- ?, [- _' d - die('连接失败: ' . mysqli_error($conn));
# A) y2 ~% m; _6 s - }5 ~; ~# k: f# ~6 q0 v2 L
- // 设置编码,防止中文乱码
' V9 h5 ~/ i5 [: j! p# k X! g0 S - mysqli_query($conn , "set names utf8");) a4 \$ k; J" }. C- u
- mysqli_select_db( $conn, 'temp' );
' }! O, h( Y0 W - $ N2 t+ ]- {7 o {9 u# T9 N
- # php中的文件锁 3 I; K% y/ ]3 P
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 , [" |; l& h* p4 _/ V: Y) W
- flock($fp, LOCK_EX);// 排他锁 + x7 m2 S5 g m! H
9 O: [; ?. [* x! c! p- $retval = mysqli_query($conn ,'SELECT id FROM ta'); ' p4 g3 B9 p& H, `
- while($row = mysqli_fetch_assoc($retval))
$ |2 C0 r2 h) T3 F# c, g+ E - {' y/ e, U! q- Y4 z
- $id = $row['id'];
/ C- Q$ p8 x( [ - }. Z8 f6 ?! Y1 t8 b
-
* E8 Y; n S: ]6 L - if($id > 0) 3 f( l4 C2 o& a
- { 1 a& d, U8 L E& B
- --$id; 4 e/ V6 y4 j; b/ H
- mysqli_query($conn ,'UPDATE ta SET id='.$id); 1 `9 N4 {3 w% q
- } 1 T3 w& a0 B, j: X
- # php的文件锁,释放锁 3 k% Q" H& U2 o% Q
- flock($fp, LOCK_UN);
# e, F" E* C$ }2 K9 t" A% B% { - fclose($fp);; l7 {1 G& Y9 y4 |
- 7 y1 { P2 w* I. W
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
2 V! d+ `9 _2 }% f - // while($row = mysqli_fetch_assoc($res))
! K$ }0 I, K& L5 ~, J6 u* S6 V - // {
# K+ X! f8 M9 O; M+ R2 I* D" A% T - // $id = $row['id'];" R# H- P# S2 D6 u
- // }4 b- U. z5 N/ u8 s0 q" p# k& ^( f
- // echo $id;
复制代码
9 i6 W: e8 q6 l* L( a, p
n; v/ @3 `9 B8 S/ P" J5 I抢券活动实例: - public function envelopeSnatching(){
$ V5 X8 e, D6 u3 ^& Q. c - $lingqu = $_POST['type'];2 J7 f) c" B. i, ^( l
- $uid=session('u_id');//用户id4 x6 u8 y) q3 L5 M) f
- if(!$uid){
' i7 k5 `# F$ @! R - $data['msg']='您没登录,请先登录!';
6 f! X+ p }" H2 Y0 [" Y - }else if(date('Y-m-d') != '2017-12-12'){( ?. t2 a( T9 o
- $data['msg']='不在活动时间内!';2 |$ Z2 r$ \/ V+ r& C
- }else{; t; O! I; L6 L0 z) K, {* ^/ s
- $hours=date('H');//当前小时数
) G' [4 g7 `- b. p8 i/ [ - if($hours > '09' || $hours > '17'){" Y9 V. Y) J. H( d) R3 t% B
- & K; ~0 e$ e5 p
- if($lingqu == 1 || $lingqu ==2){//点击10点的
6 ]6 o y5 u( O4 ?! L - if($lingqu == 1){! }' x5 I. Q' X7 U2 s: b
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
* U) K( s4 t5 C( J - if($hours > '09'){
, V/ b% x. {6 v/ z - $num=mt_rand(25,28);//优惠券金额& s1 `) J8 Z2 g3 g( B
- $id=1;( G2 e/ a6 j. _
- }" n$ R" i; M" K0 i) i
- }else if($lingqu == 2){
- Y% z- E/ W4 f - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
% U4 c9 q2 o4 |) k - if($hours > '17'){
; x' l1 G; x, Y' ~- n* i5 ` - $num=mt_rand(50,55);//优惠券金额
4 e2 M0 P* m2 E8 h - $id=2;% g2 ~( A7 X! r* y' ?5 n3 K( v
- } H4 k6 I8 Q, a
- }1 ^/ b( N) G. }5 o5 t9 M. Q6 F2 j# M
- if(!$id){
' H$ y# [8 I) { - $data['msg']='时间还没到,晚点再来吧。';3 _5 V. a; M+ m, c0 \9 L
- }else{
5 g/ [3 a4 w9 @0 y; l/ d, P - if($is_lingqu){! O4 x+ P* J& ^: S- W
- $data['msg']='你已经领取过了,留点给别人吧!';
- T: S! Z1 a; K$ e/ r* h - }else{
& c# z o- F- A# L' X! N' g+ V - //锁表( p- [8 D: B2 Y+ r$ _
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 C: x* w$ w$ B. k( [
- $active=M('active_num')->where(array('id'=>$id))->find();& O5 `; @. w! }% d+ Y
- if($active > 0){' p: ^5 P+ j l
- //开启事务0 v" C \% Q; s; g$ s
- M()->execute('start transaction');$ i/ u( Z) f7 {; `2 N0 T
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));3 b" n- Z, p# N4 P6 t+ u+ u
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
" R( a/ z/ ?! e2 X: ~. r - $members_preferential = M('members_preferential');
A" f& T! Z _ - //对应投资金额,$ {' D& R+ z2 d6 i6 `, y- W5 J# h
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));( B6 O, \; q+ n/ ~: F; [# H6 M
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
& ~- b, _7 p: } f0 p - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间$ V4 _- v0 s3 j3 D- s) Y1 X
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
7 B2 X" N9 t; e3 C& | - if($save && $add && $add2){9 {2 r8 {/ F% x+ ~- L
- //事务提交5 v8 z4 @, x( f/ R
- M()->execute('commit');
4 S9 b5 N0 P1 \2 j' t - $data['msg']='恭喜你领取了'.$num.'元优惠券';
) G: X5 Q" p- D- o, ~7 G - }else{
7 j5 X" g, p! _2 O" m! s( i+ J- L - //回滚
$ g3 q& O0 |9 R; i - M()->execute('rollback');
& _! R; f3 J% x% k8 R# e - $data['msg']='未知错误!';
( J9 i8 @, V- r" z) g8 x - } G1 n& b+ c5 Z' |6 j B- Y8 ^: i
- }else{! a, d; ~2 E. q* Y: r* d( J' [, C
- $data['msg']='红包已领完,你来晚了!';8 m- B- J& D3 ?' l D; q
- } d( h7 u. L8 ?4 V
- M()->execute('UNLOCK TABLES');
: r3 [/ r: D3 R; A$ {& C$ ~ - }
9 k7 u, o0 e, {" i) Q4 P( E& u6 h - }
( _+ U' R5 h4 q4 x# ~3 g/ q- g. L - }else{
6 n0 ]; d% ?6 F8 D2 g+ `0 N7 v - $data['msg']='非法操作!';
- v: a6 J3 ^3 O) i - }
' e; ]( ]8 Z5 ]1 B8 s; Z% U - }else{
! p' O: e! o7 |( R' ~7 M - $data['msg']='还没有到活动时间,请晚点再来哟!!';
* X g- ~5 s+ I0 ]/ h' P6 _# W - }7 |- q% L& Q9 s
- }
" M8 q6 F9 G9 ~. } - exit(json_encode($data));
! C& b: F9 f0 `6 O( \ - }
复制代码 * H6 h/ U/ E4 {8 S" `
% y9 F. B2 [; x* r! ^$ m5 m3 G5 N6 n |