模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
j8 I: Q, a `& R: Z( x& CMysql中的锁语法:
6 ^( B( ?/ ?" L/ E6 ULOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】8 c# m& h4 z0 }
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
5 D* Z. M% m# qWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞9 I, x- D) u' }, K e% A
注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :8 s! L# J* u+ I0 F
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。6 v! f- q3 u9 D& k
测试时,有个文件就行,叫什么名无所谓 总结:
/ t9 h) m: M8 h+ a4 h/ R项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:% R& n9 R) ]8 r9 F) c" ^
1. 高并发下单时,减库存量时要加锁, K! Z% K) {, L
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*; e5 w s# _9 i, i; p+ H( u
- 模拟秒杀活动-- 商品100件8 f+ R* d% |6 q" k' x9 X& j% Y
- CREATE TABLE ta' ^& a$ o+ }! }1 N& a: j& c
- (
' q' S# o: m4 O, u5 a: E) v i - id int comment '模拟100件活动商品的数量'8 j9 T8 K. N9 ^; n) q5 E! V! S& t
- );1 |* T: x+ Z& f4 o C" H7 h
- INSERT INTO ta VALUES(100);, M, o0 N" q! V3 |! g- z
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件4 W, g5 A Y; M P& A0 |
- */ : |" |: R; c( J& s- `
-
: o7 S) s, ^; N6 b9 B# c# { - // 关闭错误报告: M9 p5 W" j- Z" u: o
- error_reporting(0); - x3 P1 [ h, a; ^/ d: c! J
- ! S( |' {. t; {; E5 ^# W3 q4 w$ @
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
9 b7 B& ~ q) ` - $dbuser = 'root'; // mysql用户名. o/ r0 ^2 p% q0 u
- $dbpass = 'root'; // mysql用户名密码
4 z( c5 ?" d" ]" m7 `7 R - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);- p) {. G( G0 W |3 ~
- if(! $conn )
4 G$ I7 A& K$ U7 h - {0 N# L9 ^$ X5 E# x
- die('连接失败: ' . mysqli_error($conn));* {& `1 g' `8 d; l/ \- B
- }7 ~# _9 a) z, }! R# ]7 Z
- // 设置编码,防止中文乱码; d) z" l$ d" ] R4 l0 n( g
- mysqli_query($conn , "set names utf8");6 Q% x# u3 Q3 J# ?! s- d* ` T/ x
- mysqli_select_db( $conn, 'temp' ); # N4 q' s* \6 [8 q% a
- 5 y! W9 Z+ q& X! u3 ~% i& t1 S
- # mysql 锁
, q+ C1 h$ c3 m4 |0 Z7 ~ - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
7 }1 B7 i5 z- d7 A: @ - $rs = mysqli_query($conn , 'SELECT id FROM a'); ( P5 R! D% ], O \7 D$ M
- $id = mysqli_result($rs, 0, 0);
7 }- s. M. { U$ M- k - if($id > 0)
! i$ [- h5 o/ F5 S7 D2 o- i. ` - {
# f4 X; r6 J5 s) j- q: X3 U3 @" y - --$id;
( |$ @7 t/ w! } - mysqli_query($conn , 'UPDATE a SET id='.$id); : G R5 Q; x5 h: `: u& e
- }
" @* c2 i, R* n" @; v - 8 X* D# j2 Q* H D( T$ R! B+ a! f
- # mysql 解锁
8 p g: E' w( H; _5 I5 e - mysqli_query($conn , 'UNLOCK TABLES');6 Z9 x |6 B2 c) q
- //查询解锁后的id值
% U0 k, i& \( Z. {+ K: j - // $res = mysqli_query($conn , 'SELECT id FROM ta');
" f) O2 S5 T( \0 l J: o( y4 G - // while($row = mysqli_fetch_assoc($res))* j4 O9 N0 x7 n. ^+ i- k- i
- // {
* t+ }; }8 ^+ U7 Q! X8 _+ L3 m - // $id = $row['id'];6 U* i5 V* N r N: o+ e
- // }2 a& E B6 \1 @
- // echo $id;
复制代码 , X$ n4 D) R6 s9 V; I
0 P- [" X4 [+ N m
/ p. O1 l/ T/ I; l/ @
PHP文件锁示例: - /*
8 C. f' k1 u1 x) S* K& K" ]4 h - 模拟秒杀活动-- 商品100件
' T; z, f7 w% Z6 _' E2 ]- ]: X. } - CREATE TABLE ta$ b- C6 g& Q" A
- (
* C& T3 t* G6 Z4 U0 b0 A - id int comment '模拟100件活动商品的数量'
5 n9 F% F8 Y8 ? - );8 d1 d |1 r' A) _* C
- INSERT INTO ta VALUES(100);. J- `3 K) V; c5 R; I' e, n/ Z# J% G
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
/ L# c E+ J# @' R - */
. D/ u! U1 v4 S( p -
' y( O1 X6 y f6 O; z - // 关闭错误报告
1 `- @) e8 ?( d% r4 h2 j0 r - error_reporting(0); w) L5 x+ I% L' L2 ]
9 \( q1 f7 O m. i% C- $dbhost = 'localhost:3306'; // mysql服务器主机地址
* v1 T1 M2 j, u4 c - $dbuser = 'root'; // mysql用户名9 _! b5 ~1 a1 y7 n4 O
- $dbpass = 'root'; // mysql用户名密码" N% B, r m1 C
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& U. p1 Q/ k0 P
- if(! $conn )2 \8 b' o* E' Z8 s; X* K: E' o
- {
; p7 g3 |' p# X6 y1 _/ p - die('连接失败: ' . mysqli_error($conn));
8 Y5 f: j' w# {) g1 | B - }
1 D0 _' J& V! { P7 s - // 设置编码,防止中文乱码( e6 u" s6 J1 d
- mysqli_query($conn , "set names utf8");# C2 {# ~6 Y' W% S
- mysqli_select_db( $conn, 'temp' ); $ K0 D' m7 c* q
- * I3 X- d8 n" g1 U6 n
- # php中的文件锁 ) W+ d9 H! m. a4 S2 ]- N
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
M' w. j. D2 C/ }& | - flock($fp, LOCK_EX);// 排他锁
% G% ]- ]/ E' Z, Q2 } - , Z* |9 q7 c4 a6 P4 Y
- $retval = mysqli_query($conn ,'SELECT id FROM ta'); % i1 c2 b& I+ E# h8 c
- while($row = mysqli_fetch_assoc($retval))8 R! o+ ]; i# i
- {+ H1 W. j' {6 X0 K$ W
- $id = $row['id'];, g6 k! e6 _6 x/ ]5 r
- }% q# Q) W2 @4 O g
- 5 F- n3 X& F; }$ |; M, K
- if($id > 0)
* \2 e& r0 Q7 y; B" Z - { $ I' z' m T( [
- --$id;
; T: |/ a) \ U! Z - mysqli_query($conn ,'UPDATE ta SET id='.$id);
* I: q# K7 c, w. ~( s - } / F9 c$ n7 b/ k5 S; u
- # php的文件锁,释放锁
0 t- e' c# G+ @# ~& w# ~" H - flock($fp, LOCK_UN); ) w8 ^( X6 V: i x
- fclose($fp);
5 ^: ]" G6 v% j5 i& F - * l2 U5 _9 J- Z5 _! ^$ f
- // $res = mysqli_query($conn , 'SELECT id FROM ta');2 ^3 C5 t9 g9 g. [
- // while($row = mysqli_fetch_assoc($res))
" `" L9 V2 Y* x - // {2 X! S! [, a; ?/ i, Y
- // $id = $row['id'];5 q, P @/ A5 X, V7 d
- // }/ O+ w5 Q/ g$ G' T% W& c
- // echo $id;
复制代码 % M) l& v9 y- C8 H& |- Y; S
0 j2 \; ^7 T& }" |" e$ \9 V1 r3 E抢券活动实例: - public function envelopeSnatching(){$ C! Y: y: w8 O3 _( S- ?& h7 L
- $lingqu = $_POST['type'];7 \0 z) D6 f& ~+ l3 C$ @
- $uid=session('u_id');//用户id
+ j/ r# {$ }# ~* a( I - if(!$uid){
2 [: d3 [$ v3 I8 c - $data['msg']='您没登录,请先登录!';) i1 _ |* @# R
- }else if(date('Y-m-d') != '2017-12-12'){
. N1 a* r, T, n* ?% ]9 l( l& @ - $data['msg']='不在活动时间内!';* P( L7 q& F: c
- }else{; D" z: H% q8 \: K# ^
- $hours=date('H');//当前小时数7 i+ R- T3 [6 ?7 a' J
- if($hours > '09' || $hours > '17'){; }+ y0 c1 G) z# V$ k7 \& g$ s
- n/ D9 o# E6 J; Y3 G# o- if($lingqu == 1 || $lingqu ==2){//点击10点的
) G4 V- O, y0 W$ P$ z" N# M - if($lingqu == 1){' j6 h! E3 f& z+ Q3 A, q/ {9 q i
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过: v+ I( Y# N' P$ @5 Z
- if($hours > '09'){+ W4 G C- V1 t8 {5 P. i7 ?
- $num=mt_rand(25,28);//优惠券金额/ f6 \+ I f H) S9 o* Y1 o$ h
- $id=1;
! n8 c# ]0 u$ x4 C/ r6 } - }
; z; ]5 a8 _7 A! x; P4 Q - }else if($lingqu == 2){ s3 j4 T! J0 p# h
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();! z. w9 z" n- O0 C
- if($hours > '17'){& ^; T* V* g0 w, P
- $num=mt_rand(50,55);//优惠券金额
0 l, F) ~% `- v1 ~1 E - $id=2;
4 S& W/ h. X3 |$ H9 O* g& G9 y - }4 F# i9 w1 {, C9 ]9 Y& R
- }
" a3 ~+ A# D/ \ [. S - if(!$id){
9 B3 w. k" [5 J. S - $data['msg']='时间还没到,晚点再来吧。';( T! i9 P& b0 ~# K4 v
- }else{
) J8 _( B/ c9 h) D W6 J - if($is_lingqu){1 z( Y$ v# e# r
- $data['msg']='你已经领取过了,留点给别人吧!';
, j, u7 r: N! M! x0 k - }else{
6 k |4 d5 \; B5 V0 H - //锁表
I4 c/ u$ k- _( m8 f$ b$ l - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
5 g# E; ~: i$ A6 W/ I" F$ O! U% [ - $active=M('active_num')->where(array('id'=>$id))->find();2 i) h* c& K. C( T4 i/ m
- if($active > 0){
% s# P0 ~$ W p# N a6 a/ C - //开启事务
: z! }3 z- g/ ]4 \- X) r/ S - M()->execute('start transaction');3 m, r! r: {. d- q, G% ^. j; l
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));: d1 Q: f$ j$ i- J! X
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
) L. _; }+ r* |: `5 } - $members_preferential = M('members_preferential');
( U! K5 V% T1 q3 y& v- p - //对应投资金额,7 J9 n" k5 y" H9 R! R* j
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));7 S4 U) G$ V( J- L. D, o1 X
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
, t4 L: f/ E6 C: p" U* J - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间, I* o1 |2 u9 ?6 U# w9 l" k% C6 Z
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券2 u5 [# j* a9 N
- if($save && $add && $add2){
* ^. @$ ~# ]5 Q, k - //事务提交
+ m/ i+ V& m; {- o: | - M()->execute('commit');" R% T C, ~( G7 M- q Y5 l
- $data['msg']='恭喜你领取了'.$num.'元优惠券';3 V, G$ r% V8 L* q
- }else{
# }( q6 K" g: I' `& P - //回滚
/ V8 e8 [& S. }# }( T - M()->execute('rollback');8 t2 d8 g/ e ?% o8 T* U$ f
- $data['msg']='未知错误!';9 l/ M. ~( e+ [+ U) M
- }
7 `+ u" y( _, J( C0 X% r - }else{/ ?9 Q# v+ M0 B4 q5 c3 \
- $data['msg']='红包已领完,你来晚了!';
) Y# H% U: A, z6 K! A* ? - }
- N g6 G2 b/ r4 k ^; Z - M()->execute('UNLOCK TABLES');
3 m* ]# V2 J, d6 g - }
& A( a5 T' I' I- g, V# f; J7 n# W3 Z - }5 d& w1 h& A- L9 v @# Z) }
- }else{
0 B! x# U9 s9 [2 C( F2 U, V - $data['msg']='非法操作!';1 c# q' Q' Z7 T
- }! H; W4 M6 m, L! ]& F* j' s
- }else{
0 ?# X8 G7 g9 k! O, l - $data['msg']='还没有到活动时间,请晚点再来哟!!';0 n5 h" T1 Y6 n# T2 q+ ]
- }4 U9 k' i* \ I! F t
- }
/ r9 q6 k9 c! J! ?0 J+ } - exit(json_encode($data));
F9 M |- x+ |, [4 R - }
复制代码
4 `; d$ ~$ N% [0 }) ?7 V$ F4 Z5 L: @" T
|