|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
) _6 d* S+ u2 O- m L6 QMysql中的锁语法:
" ?9 ^8 R* {7 H6 G5 Z2 mLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】/ R( }* ], l+ d2 O# `9 F# K" @4 A4 C
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表" s, w: a k, ]9 I! r
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
. O9 F: \$ V4 x* v. g* h注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :9 e! ^& E5 W2 b2 u3 {
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。2 e7 \$ v( W2 ~% ^( R% \
测试时,有个文件就行,叫什么名无所谓 总结:
# D( f8 s1 k' ^3 P+ ^. j项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
K( h$ \2 c5 y- j1. 高并发下单时,减库存量时要加锁( n* L I! T: g
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
0 W7 u1 v9 n6 ]6 a- H( b9 }) k. ? - 模拟秒杀活动-- 商品100件- ?" X% ^: t' B. [9 A
- CREATE TABLE ta' D6 G: a8 F9 p
- (* J& `6 G1 g% A
- id int comment '模拟100件活动商品的数量'
\4 `( \2 }/ k7 _) N - );8 M9 y& O8 _# O P5 j3 t: k$ N2 r
- INSERT INTO ta VALUES(100);
" m' D; t3 r% u6 D - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件/ l6 w% {8 r$ J" \/ o6 e6 _ u- Z
- */
1 N* a& P" ?7 Z - 3 J: s4 q$ k; U2 { B( ]3 s
- // 关闭错误报告
, s/ z! h& q( C - error_reporting(0); 2 r6 N" T* u- }
- 5 i& v: d$ a3 v4 I4 x
- $dbhost = 'localhost:3306'; // mysql服务器主机地址1 r9 [$ L& |9 U% Y6 @7 Y
- $dbuser = 'root'; // mysql用户名6 q* i$ B% r& Y5 }* A
- $dbpass = 'root'; // mysql用户名密码. ?" f H% A7 v2 {9 C3 n
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
1 [ n, }9 Z, v2 j* S - if(! $conn )! h t2 ^* _: i9 p6 Y7 A
- {! a3 Y7 g' K% }9 s
- die('连接失败: ' . mysqli_error($conn));7 x' _( k% c9 Q, u4 N
- }
\: z5 i5 c+ C& H5 }( H# ^ B - // 设置编码,防止中文乱码0 K% H* |$ J: }' B3 U5 A
- mysqli_query($conn , "set names utf8");
8 C3 k3 y- j" r8 k6 H4 p* [, f1 b- j - mysqli_select_db( $conn, 'temp' );
2 n: X4 J L2 @9 f5 u7 T/ i1 E
1 ~6 A1 o' @$ z c- # mysql 锁
0 r' d6 V |: ^5 E( Q+ _! s - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 ; s: F$ d5 A, O9 D) d; A
- $rs = mysqli_query($conn , 'SELECT id FROM a'); 6 j( i% U6 y& b2 E
- $id = mysqli_result($rs, 0, 0);
o; s) e$ ^1 R* J+ i0 a - if($id > 0) D( s4 ~2 k. R h2 j
- {
! u9 a& l/ B5 w7 D6 `- V - --$id; * K9 d+ {! C5 F* s* A/ L
- mysqli_query($conn , 'UPDATE a SET id='.$id); , }; U# B& F( O* s& e
- } ; t3 a% O7 u$ d1 b! t
- 2 [0 P9 e5 r4 \! e9 h# I
- # mysql 解锁 , g" R9 }% K) F8 Q% H
- mysqli_query($conn , 'UNLOCK TABLES');
2 o2 K% i( {5 d; k4 G - //查询解锁后的id值
" t6 a' `1 r) n) } - // $res = mysqli_query($conn , 'SELECT id FROM ta');
8 i( _+ a) F, M9 R* p - // while($row = mysqli_fetch_assoc($res))7 ?9 T# ^& Y; S: n+ \! y N
- // {
# X$ n+ |7 s: P% O7 ?0 ~: @ - // $id = $row['id'];5 |+ ]/ t- x9 Y" M
- // }6 i* o. R+ ?9 c; r) x8 C
- // echo $id;
复制代码 7 p7 o* ]3 A5 v
' n w* y" r# }; G2 L
- F2 e# k1 a& U$ I6 j0 X* K
PHP文件锁示例: - /*
$ ^4 }8 h. P: W - 模拟秒杀活动-- 商品100件" n! q5 z$ K' N& Y/ l; I
- CREATE TABLE ta
6 R. X1 M+ s. T I2 | - (# ]9 w$ h# z5 I) ?& {2 W; X
- id int comment '模拟100件活动商品的数量'
, ^ b: \& n, w1 L6 y$ a: R - );
# ]/ O' V4 u: @3 P - INSERT INTO ta VALUES(100);
" U. m4 V; T/ L* T& `( Y( [ - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件' T7 A% C: T8 U' l* E# l; {
- */
+ S& U9 y- g& B5 B/ q$ r6 l2 Q - ) K% Z/ ?1 [" b, ^* Q2 K1 X5 J* {% i
- // 关闭错误报告6 L2 y8 i, o* S3 L4 j* _5 [
- error_reporting(0); ' o7 G5 z- v" W" q7 {
. |3 v5 N& I3 L9 \- $dbhost = 'localhost:3306'; // mysql服务器主机地址/ M/ z) R/ R+ O' ~/ C
- $dbuser = 'root'; // mysql用户名
! Y, c1 z6 S6 {; e; G9 v3 e& I - $dbpass = 'root'; // mysql用户名密码
. a. j8 Q6 F- o - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
/ q1 Q8 H2 r& ^8 k9 P - if(! $conn )& P# x- B, r; g, R; u" Z* W
- {
R, ]; w5 \1 [! [5 ]/ D - die('连接失败: ' . mysqli_error($conn));
0 T- ~* T& y3 f! i - }
& O2 N# u5 v! F6 n Q% M - // 设置编码,防止中文乱码
" w$ A; T$ q8 p' a; `. I* Q - mysqli_query($conn , "set names utf8");
) u9 ]2 X0 r& g/ w" r% b1 Z- j - mysqli_select_db( $conn, 'temp' );
- D" P" {- Q; f; E
: c' ] J; u% r' [# y/ n- # php中的文件锁 6 U! x, \* D8 e5 [' M- U
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 9 L @: M: u5 A; `2 D
- flock($fp, LOCK_EX);// 排他锁
) @5 b* V' Y l Z: j
3 C6 h4 G/ c% [& r- $retval = mysqli_query($conn ,'SELECT id FROM ta');
5 {1 c' o# q0 A, f$ }6 g - while($row = mysqli_fetch_assoc($retval))' L3 m4 L% a$ S2 k5 s% l8 |. P
- {; M3 J* m- l4 c& H0 q( P
- $id = $row['id'];
" z6 I! w, Q4 Q- \ - }
' K- Q: U/ s# P+ j2 ? -
+ ?+ d8 S( @% f* }# M - if($id > 0) 5 O7 y* }/ ], B" U5 y
- { 6 X" H% ` d# q9 b0 u8 } e
- --$id;
2 Z4 a* a; g9 j$ L" d - mysqli_query($conn ,'UPDATE ta SET id='.$id); * q) t* b0 A/ g- z$ K, _ x& t
- } , f1 l5 q# ^3 S2 f
- # php的文件锁,释放锁
) Z. | M { N0 K3 `) ] - flock($fp, LOCK_UN); ) F# R& w# J f6 D! X
- fclose($fp);
- j2 A& Y1 s9 b2 J# Y0 w- k
9 X2 U! }7 ]+ X3 L# F0 \# q2 }, k- // $res = mysqli_query($conn , 'SELECT id FROM ta');
3 ~1 a# m5 @1 C7 y* M - // while($row = mysqli_fetch_assoc($res))/ r# S' D3 }* t
- // {# i* Z( l, E8 ~- m$ w
- // $id = $row['id'];
. z4 [" y0 a% `/ u* o* F' @ - // }5 H4 r# p* p" i8 p/ Q3 i0 K. P
- // echo $id;
复制代码 * r! }4 _: ~; _% a
; E; z4 E( w i抢券活动实例: - public function envelopeSnatching(){
% s) ]$ A' s. k, l5 Y7 r" p" { - $lingqu = $_POST['type'];
! G. K2 N+ D/ `# n - $uid=session('u_id');//用户id
, [! M7 b$ V3 d - if(!$uid){, A/ _! H6 i M$ W0 W% w! J5 k
- $data['msg']='您没登录,请先登录!';. i* v. a3 [! f# y. V8 H
- }else if(date('Y-m-d') != '2017-12-12'){
) u# Z+ i8 V- E g/ I& Q - $data['msg']='不在活动时间内!';# G' x" H4 o4 y* b
- }else{: o/ z# `+ m; ?1 y5 k$ `/ u
- $hours=date('H');//当前小时数, _. g7 Y* P" G- V1 N e8 V
- if($hours > '09' || $hours > '17'){: {* f7 l/ w |
- % a8 ~! e. Z" s7 I& F) R
- if($lingqu == 1 || $lingqu ==2){//点击10点的+ o# ~4 Y' |* G5 Z* ?0 X
- if($lingqu == 1){
3 z! E1 E q) z- j( I - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过6 j0 ^( H( |9 g
- if($hours > '09'){
* J) V3 V+ C: `! l* I8 R1 } - $num=mt_rand(25,28);//优惠券金额
8 {3 c, g- d, l1 [8 L - $id=1;
9 A4 \2 N) t" x2 R - }7 h8 `5 A: A0 s3 O9 p( [, x
- }else if($lingqu == 2){
) r" T# J" r- ?% z- t - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
0 c( W$ d1 e# I' S; `% y! j& \3 J: Z - if($hours > '17'){
) J" E7 F$ `4 _. Y H - $num=mt_rand(50,55);//优惠券金额3 [3 Z$ g7 E/ t& b3 |& C7 U. f' T0 t
- $id=2;
- j/ f& R7 G' ^+ F" I8 t6 N - }
4 C$ \6 P8 `* n - }
( D* _: K6 L9 i. t! M4 H - if(!$id){
4 X' i" C. _& D% T4 h/ d7 A, w - $data['msg']='时间还没到,晚点再来吧。';3 _1 M. n* ?3 m4 `, Z5 L; d" W7 S6 G
- }else{
: X1 l5 `5 g# n" o - if($is_lingqu){
* T: l+ r0 k( |/ I; `# P - $data['msg']='你已经领取过了,留点给别人吧!';/ f @! f S) R" E$ A u
- }else{1 z* t. `6 r- \0 c# q' s2 o5 D& ^
- //锁表
4 H5 R1 M( S/ a8 i% m - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
# F! I# d' I7 S' ^- A9 h: t/ G9 w - $active=M('active_num')->where(array('id'=>$id))->find();: J8 {( g4 S; o/ h) J- R
- if($active > 0){
' ^! j% {+ Z9 ?6 V/ p - //开启事务4 T. v# T+ x% C. V! K
- M()->execute('start transaction'); N! d! k! i% a+ K& W; c
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));' g1 P4 J8 E, a% q
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
+ f, D+ R8 A" p# d1 Z/ H" ~0 K3 q - $members_preferential = M('members_preferential');
* h( j2 Q$ M3 @3 ` - //对应投资金额,; `3 C7 T# x+ U9 u" D! p7 I
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));2 H5 ^- O7 i9 C c c; S$ K, u
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
9 A7 h% I- e9 z u/ v2 ^ p - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
. j: z% z' M' w; O( X! W - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券1 _- C+ k1 C) n* R: q. J) { }
- if($save && $add && $add2){) C$ a( g: U9 M$ S2 d
- //事务提交
$ X. P' y5 d1 i/ b/ `. B - M()->execute('commit');
; m& n/ v* B- p# b! i( J - $data['msg']='恭喜你领取了'.$num.'元优惠券';+ W$ U+ j. d2 B3 O a* k
- }else{/ h- N6 [$ S4 [% l7 B2 L- Z- O8 _5 h
- //回滚' R8 x+ L7 z: u/ h3 M
- M()->execute('rollback');
0 Q( Y3 B1 ?& Q - $data['msg']='未知错误!';4 Y; C# L) ^* b* `
- }- R& H3 L: M) L) M8 I
- }else{. ]9 k2 G( U/ x# k( h0 ~. v
- $data['msg']='红包已领完,你来晚了!';/ X/ w! _+ F7 i) T6 Q
- }
1 u1 ~' {7 V/ ]+ z% D - M()->execute('UNLOCK TABLES');' T) f6 _& m' m/ B Q) T5 [
- }
0 X! @" x: n; c' l3 k/ ` - }
0 c' X/ X* X( r2 o# J o9 ? - }else{3 @% b' R0 J) ~) g; {* n& U
- $data['msg']='非法操作!';$ L# n" s0 p9 ` h) O2 d$ q
- }% L$ Y4 B* K! V/ K0 O
- }else{1 v N. Z/ s. m0 M, T* h4 y3 P" I5 N/ K
- $data['msg']='还没有到活动时间,请晚点再来哟!!';* e. y/ g; x/ B; b8 w2 @
- }) r6 F6 x0 n7 L/ L. j( h( N
- }$ h& f4 U/ q7 ^1 ]& j' }3 A
- exit(json_encode($data));$ ~4 m" Y4 W& E' G* O9 o6 y
- }
复制代码
: u" Q4 Z8 t2 ]) X4 c# U1 j2 x; Q
+ i, P3 O8 G9 b8 _ |