|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 , o& [$ q9 J1 s6 X
Mysql中的锁语法:2 k, T3 j, w* T
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】0 \. ^1 t+ ^* v( B4 D# P8 h
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表- A* D! I* g/ I: K" X
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
) U5 r9 T& G4 f4 d注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :5 w) h9 U1 w0 H. E( A
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。( a! z4 B& k; t" W& A: P; _5 p
测试时,有个文件就行,叫什么名无所谓 总结:
1 g; w { j& D5 L; T0 h. H项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:8 `/ n4 i8 q+ T* d/ U2 s" y( I
1. 高并发下单时,减库存量时要加锁" R/ @: I- P/ V( I6 T
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*- ?6 Z$ Q9 [5 x9 j' r
- 模拟秒杀活动-- 商品100件
; [( }* q- n: _# \6 u, n - CREATE TABLE ta
/ H% S; {. O' d - (
% K& S8 H2 [* P, d' M0 f1 t - id int comment '模拟100件活动商品的数量'' X5 V" c* q: V+ D0 A4 v) |- z: a: s
- );! y, {6 m& I6 t# t; i: p
- INSERT INTO ta VALUES(100);
+ g3 x0 C( O4 m4 g - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件; b# `7 N. Z; N2 D5 t' k
- */
. Q0 ?. P# _! b! [) M - ) @5 o, D3 ]/ T8 d' g" \5 U
- // 关闭错误报告
0 d _9 F6 Z/ `. T4 T; E2 `& T3 P - error_reporting(0);
: a) \2 F7 K4 ~) T" M; B
3 _" L E7 |! B# b9 M u4 j" q- $dbhost = 'localhost:3306'; // mysql服务器主机地址9 g( z. }- z* O
- $dbuser = 'root'; // mysql用户名
5 @: a- o+ c9 s& U6 U - $dbpass = 'root'; // mysql用户名密码
4 l+ O) Y; o( L0 Z( m+ ^5 g5 O - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
1 a q1 k# A2 N% d) ?0 N - if(! $conn )( \ \+ Z/ {& Q' g3 K
- {
! ^7 S' W! n+ G - die('连接失败: ' . mysqli_error($conn));
7 | h4 Q( _1 \6 l, I - }
/ Q+ v# N2 Z3 z2 [. E - // 设置编码,防止中文乱码
" f* C8 B0 w8 [" k% I - mysqli_query($conn , "set names utf8");
* \/ c) R! c! K. D; }3 m - mysqli_select_db( $conn, 'temp' ); , `$ _' k* C$ V4 Z- q9 q" a6 x+ k* P
- - l9 w) f% w% @# M, a; j0 u
- # mysql 锁 8 s* @: ]6 |4 V8 h' N
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ) O. g) k0 z' u" b( ]6 B* P
- $rs = mysqli_query($conn , 'SELECT id FROM a'); & ^. i3 N" U1 B. p- r. q% l' S
- $id = mysqli_result($rs, 0, 0);
9 Q# j _" r! E& b$ e - if($id > 0) / L% e7 L, A0 E, F0 h. _
- { / J, E/ K `( _, J% L, \
- --$id;
: } n; }; R& `: Q9 _ - mysqli_query($conn , 'UPDATE a SET id='.$id);
5 P# q2 f d+ N - }
9 H5 l$ x6 g8 c
. _' @) m, d0 r* I! v- # mysql 解锁
1 v# `- b6 i7 ]8 E: l - mysqli_query($conn , 'UNLOCK TABLES');
# _6 @' H( U1 m5 |7 H - //查询解锁后的id值2 J% C$ h8 T. P- A) W7 n( V. V% @
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
: \7 C9 [: w1 G" o3 E, k8 q - // while($row = mysqli_fetch_assoc($res))0 s! ~$ j0 ~0 Q7 `+ P4 m. R
- // {
, ^9 o# E, ]: a1 m: r - // $id = $row['id'];5 T. ^* I# A6 ~. X2 z6 z
- // }
9 P; R( Y9 I. F0 V' L. m - // echo $id;
复制代码 " K7 v0 T: R( d$ V' }
( J% L; ~( A) v' \$ M
0 h- z4 C! T! [. |: X+ p2 W
PHP文件锁示例: - /*; D- w* f1 k. q- }9 E4 x1 m8 R% i0 y6 y
- 模拟秒杀活动-- 商品100件$ C& h/ D* G c4 A" @9 N6 |
- CREATE TABLE ta
. i% j; h, u5 d O - (2 J& `: T7 `7 L2 |0 F/ c. a
- id int comment '模拟100件活动商品的数量'7 B- g- m( N+ H% j
- );0 T. i1 f3 L. F- h5 Y1 U- M4 L( u
- INSERT INTO ta VALUES(100);
9 G6 T6 p: t' `! m: ` - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
1 _& j* r% e7 D$ G: y$ ^ t/ i$ T9 a - */
w7 z2 l {) a. T; X8 i - - o c, t# D4 o! W
- // 关闭错误报告6 V( O" B# D [& A, z
- error_reporting(0);
' V5 H% d3 N% V$ c
3 t* N% q: b7 u8 s8 O- $dbhost = 'localhost:3306'; // mysql服务器主机地址$ x; F* g. a [1 r8 k
- $dbuser = 'root'; // mysql用户名
4 f3 S2 n; [9 P4 P - $dbpass = 'root'; // mysql用户名密码
( C* w# B1 o. v' g& Y9 p - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
" e, p0 s% j- o$ l; e( p - if(! $conn )
* K& f+ ~/ Q5 Y1 s) C8 p - {: _, G( D+ l" l
- die('连接失败: ' . mysqli_error($conn)); N2 B0 p6 J* U# f. T' h# M7 [7 W
- }
8 I% U# P3 B2 B( `$ m - // 设置编码,防止中文乱码
" P1 {. d: q, t - mysqli_query($conn , "set names utf8");
! g; I! @+ C9 D, d: u - mysqli_select_db( $conn, 'temp' ); - A; Q. t( l- o/ Z
- $ m. f1 d/ F6 {0 C: j0 L
- # php中的文件锁 5 K2 V! @/ a2 D2 _+ b4 |3 Z/ [
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
. b; w; d+ v% ] - flock($fp, LOCK_EX);// 排他锁 3 F( y0 {7 w( c- _
# e: r$ e6 G. i- $retval = mysqli_query($conn ,'SELECT id FROM ta'); : ^2 F( {) X6 `$ w& \" F4 N
- while($row = mysqli_fetch_assoc($retval))) G. z9 ?9 h' x3 M5 \$ x
- {. E H r: d6 L
- $id = $row['id'];
. o0 { _% f! q8 e9 w - }( }& k0 P, E( y3 |
- ( x; l0 N' N( s7 ]* L( [
- if($id > 0)
$ k J+ P0 G% u! T7 m" _ - { 5 ?! k9 f- B; \: ^
- --$id; 7 _( k5 j7 n& [" R
- mysqli_query($conn ,'UPDATE ta SET id='.$id);
" h/ d$ a" d6 r) G - } - r" X& P) B# O* k1 E+ S7 P* j6 m
- # php的文件锁,释放锁
. ~' p6 U1 l- c( I; ?. x - flock($fp, LOCK_UN); 4 } c$ m7 R; Q) t8 N" U
- fclose($fp);! P. e3 I# |; A# W2 P3 e
- 3 l% e3 P$ T7 g3 ~! d. d
- // $res = mysqli_query($conn , 'SELECT id FROM ta');0 t, Q5 D+ C1 {5 L& U3 M8 U
- // while($row = mysqli_fetch_assoc($res))
0 [2 f6 z8 O" o - // {
& W0 `5 {# D8 E- T5 i$ m* A - // $id = $row['id'];- ?2 M3 G- k M" [0 D$ F7 n
- // }
5 [% p% T5 z+ b* n9 g - // echo $id;
复制代码
: S6 K L7 f! q- b ~
7 \9 ?9 K+ R/ U+ ?) O( c( v抢券活动实例: - public function envelopeSnatching(){5 ?- v" k) g% N0 G
- $lingqu = $_POST['type'];
3 B% T+ S9 D, B- J4 ~& E( \ - $uid=session('u_id');//用户id. W$ [/ P p: b7 `: B
- if(!$uid){
1 ~' R& \! E. P4 K( E - $data['msg']='您没登录,请先登录!';
; n; c! ^$ f5 I" i - }else if(date('Y-m-d') != '2017-12-12'){
2 `/ D% \3 K! V7 k4 T- z9 R8 i - $data['msg']='不在活动时间内!';
3 w7 G6 u; D4 g - }else{
9 s, y' z) d3 t0 v - $hours=date('H');//当前小时数% A8 t" B7 {9 \; j; T) l
- if($hours > '09' || $hours > '17'){
0 ? _4 n: h- k4 p( {% P! w1 }
1 E. O- q% e/ v- if($lingqu == 1 || $lingqu ==2){//点击10点的( g9 W! Q; m( ^# D8 I
- if($lingqu == 1){4 @& E3 ?$ I6 ^" @) c8 q, i" G
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
$ ?; v3 N! f# t. F - if($hours > '09'){( R# {: j3 D3 |: h8 ~ d9 H
- $num=mt_rand(25,28);//优惠券金额9 q! t# s: f* |8 @
- $id=1;
- n6 U/ p# P" j - }
% Z/ c8 w! O$ t" E+ k. p - }else if($lingqu == 2){' D- D6 B' x& A; u0 w9 c
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
! o0 l5 G; Z( s! E - if($hours > '17'){
( S4 f5 s1 |- K ? - $num=mt_rand(50,55);//优惠券金额
% ~" y4 P9 P m. c1 } - $id=2;/ J5 G& `* U- n; y) W
- } R/ y" q) b. O4 ^
- }' ]2 F/ u D4 @1 K) |
- if(!$id){
% l5 h/ h) ~5 Y2 K$ e- e - $data['msg']='时间还没到,晚点再来吧。';
4 F- e8 K6 R2 [# f3 y& Y8 r2 u - }else{7 W5 B, @2 u* z6 m. w4 b
- if($is_lingqu){; a2 ?. t; [' T
- $data['msg']='你已经领取过了,留点给别人吧!';9 \% ^0 s" |2 M' z, E/ \. Z
- }else{
5 }1 b1 M# p6 ^+ T5 r3 C4 Z- b4 a - //锁表" [) b$ z5 q$ d+ b# g
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');3 B; }6 L4 e: Z
- $active=M('active_num')->where(array('id'=>$id))->find();7 m: T+ `0 [# n1 o, T
- if($active > 0){
1 `$ R8 q' {3 Q) g8 k4 W$ ^ - //开启事务0 F# i) d9 F( l& B( K
- M()->execute('start transaction');
' e$ P7 Z& L n% l - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
& J( \. [9 U% ^9 p0 s% b - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));& c; R' s) V4 `2 x& B5 e. E2 m
- $members_preferential = M('members_preferential');- Q5 M. p- T" ~1 ^7 T
- //对应投资金额,5 x4 F* T' l) U8 t) w7 C- n
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));4 ^. j Q8 |/ y ]
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
- I, W8 J9 {. a; T - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间4 `: P% m* [* ?6 R9 _
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
Z3 c7 `/ I* p% k6 X4 x - if($save && $add && $add2){
) a: `& E8 F; J2 D& [: Z - //事务提交
) M" q- \3 }# D - M()->execute('commit');
/ d ~- N$ [( k0 i" F6 n/ c) O _ - $data['msg']='恭喜你领取了'.$num.'元优惠券';, |3 A& \+ t B+ Z& O$ N
- }else{
7 G3 K4 P) l7 y) ?" y. z - //回滚# G7 J/ B( i( ~5 S
- M()->execute('rollback');
. q/ R$ }. P0 Y& Q! Z: U3 t* ], n - $data['msg']='未知错误!';) i; q: s; s* `9 D. P5 J# Z" G& ^
- }/ P$ @9 \. O% @; @4 v
- }else{' @! G V; A$ c& h6 J) o
- $data['msg']='红包已领完,你来晚了!';
7 g. O! q4 _0 I% L- s - }
8 K8 |- l2 m3 _% W; L5 y - M()->execute('UNLOCK TABLES');
! o# ~( C; |- M. D0 H - }" o/ z( w! ]- d5 i
- }# O+ s+ t2 C( M! a6 `& g$ t
- }else{
5 u9 {+ p& f. B# r3 v: f - $data['msg']='非法操作!';3 O9 E" m# s& ^7 g
- }
3 \- S# t+ w8 v' d: J( l9 u - }else{
* f' u5 ]3 N7 R* w: r1 h0 t - $data['msg']='还没有到活动时间,请晚点再来哟!!';$ O& @; f) a' ?; e+ T
- }1 X) Z$ j5 m) M( t& j
- }
9 K( p* h* n" } - exit(json_encode($data));
8 `# G2 Z7 C5 B - }
复制代码
+ I; ~7 G _# L& c: v
8 Z9 l8 T: u& b3 f, V8 F |