|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
# g, H, y1 {. z6 @6 K7 pMysql中的锁语法:: l4 U) D0 d) k% f& Q/ B! \
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】- y S7 E; W. h' ~# M
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
6 A! |- L- A+ n6 G3 r! j1 fWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
, H% t% y8 m; T- H) \9 A5 A注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :4 l0 l3 k( W ~; w0 ]/ w" \0 ?
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。' |- o. n2 p& Y5 i1 k( s( Q
测试时,有个文件就行,叫什么名无所谓 总结:
$ Z5 \( P7 n3 P1 J项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
i2 \$ d: T9 j1. 高并发下单时,减库存量时要加锁0 [8 R1 q% y6 @6 l1 }
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*- o. z3 G7 @! t; B. {% ?3 f
- 模拟秒杀活动-- 商品100件1 B' \% p- r' ` V( U/ Z$ c8 M
- CREATE TABLE ta
$ \3 Q6 x$ Z9 Q% p+ {+ \+ i - (0 R) x; M& L5 t8 T4 s" b& S% M7 ^
- id int comment '模拟100件活动商品的数量'
M4 `4 B$ S$ f- J - );
1 I3 c2 Y J5 ^& ?% U; k, N: s - INSERT INTO ta VALUES(100);
* q* M9 C z W+ S0 l( J- o5 f/ T' | - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件! s* O7 `4 Z: N
- */ ; a$ D% u4 ]1 ^( [
-
0 O4 k% _$ k( F: ^ - // 关闭错误报告
4 e" I% w+ q5 k8 B - error_reporting(0);
7 ^2 V1 \3 d; N2 i; a& F - ) D3 l d- A) U
- $dbhost = 'localhost:3306'; // mysql服务器主机地址
. e* H/ w8 p% S0 x! o+ H" y - $dbuser = 'root'; // mysql用户名
$ N7 i7 g, k9 y2 f - $dbpass = 'root'; // mysql用户名密码
$ Q( ~0 [+ ?- h: S1 M0 O* A - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);$ Z- Y, C' G* c& l* _: P7 M
- if(! $conn )
: R4 S9 l: a: h* b+ p" M - { Y4 E1 I: S( a9 J
- die('连接失败: ' . mysqli_error($conn));; c5 l/ ~) b$ h2 \4 W# `1 J
- }
9 n* P& `2 k( F$ i: J - // 设置编码,防止中文乱码1 W- B6 _' K) P' z, c
- mysqli_query($conn , "set names utf8");
% ^; X% q9 @" V - mysqli_select_db( $conn, 'temp' ); : u W1 n6 ]3 Q* L( O8 d' T' K
0 V; S; R; M4 N0 j! K* M- # mysql 锁
5 G; Z( E5 g; b" u4 j - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这 5 E- e. h8 p* v5 S. P5 o K
- $rs = mysqli_query($conn , 'SELECT id FROM a');
. t% d/ ?8 n8 b6 u1 t ] - $id = mysqli_result($rs, 0, 0); - c6 T- h( }4 z
- if($id > 0)
. R% L6 A3 H6 | - {
7 g/ Q% v9 s( q7 t3 }& F: V% E: l - --$id; . g8 Y' y1 t5 A2 X. ]& ^
- mysqli_query($conn , 'UPDATE a SET id='.$id); + u$ F: K3 {8 e& d& P9 p; P$ L/ [5 h
- } " ` p3 S. d" w# }/ D8 e0 {
/ T0 y) L3 o# D- # mysql 解锁
. O9 }5 v5 B- X& G* A - mysqli_query($conn , 'UNLOCK TABLES');
+ u2 z' B n4 N( O - //查询解锁后的id值/ D H7 w, F+ I
- // $res = mysqli_query($conn , 'SELECT id FROM ta');" r( T! j4 h4 R A8 ]3 W
- // while($row = mysqli_fetch_assoc($res))- {( G; V+ G: {: }5 _' A
- // {
' ?) Y+ b! d" h( m! a - // $id = $row['id'];
8 x: V* F' M- c* i2 N8 C" _+ h - // }
4 u0 w, }8 B( m( O5 z, W( d7 y - // echo $id;
复制代码 1 `' O7 O3 d5 r0 m# K" s
9 s: r6 L9 d; d
* w3 I9 K1 m- ]2 F4 K1 ?PHP文件锁示例: - /*& z0 x7 E1 j# g* W3 G
- 模拟秒杀活动-- 商品100件
5 i7 G: Q: r, W9 C! |+ Q - CREATE TABLE ta4 w/ g1 J2 q2 g
- (
% O% Z& H6 i6 l - id int comment '模拟100件活动商品的数量'2 U& c/ F- F' h8 r# j% d8 u- l
- );
0 Y# W4 R7 E/ u - INSERT INTO ta VALUES(100);1 A& K2 b3 ~. ^, D+ A% M2 Y
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件- o& c4 U; U# b3 f3 X c9 U% P+ {
- */
" G) j: N( N5 t* m: i5 ` -
4 r3 }4 j7 b& Q - // 关闭错误报告
3 K; y8 o" u0 \! o- f( q - error_reporting(0); : b5 I6 f) o4 A% t9 R
# M- M( ~3 Q. V# z7 D. ~- $dbhost = 'localhost:3306'; // mysql服务器主机地址
/ r" }" P/ w: n0 n) Q - $dbuser = 'root'; // mysql用户名
_4 F+ a' K/ d/ Y1 Y1 z - $dbpass = 'root'; // mysql用户名密码* ~2 o( {9 I i9 \( J# ?$ z6 S1 n: l9 H
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
# f9 i7 J G4 P# J& l2 p' P2 m8 a - if(! $conn )0 m0 F) p0 e3 A
- {
% G, ~# e+ D5 q - die('连接失败: ' . mysqli_error($conn));
# |9 `* c: c' v5 v# G0 J* L - }7 P+ n+ B3 F- G2 j
- // 设置编码,防止中文乱码
) X1 i! P% _5 R8 y) I. U - mysqli_query($conn , "set names utf8");
9 K- F3 i+ q2 s+ | - mysqli_select_db( $conn, 'temp' );
R3 _' t( v( A# A9 Y - & A7 s. ~( f) h+ O% V9 A
- # php中的文件锁
, m, R, U% n& z) [- M$ V - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
% O" L* H1 ]/ G6 ~& o! K - flock($fp, LOCK_EX);// 排他锁 % K5 }! J2 y g; V" |
; n8 L3 `7 u. s5 e+ ^( M- $retval = mysqli_query($conn ,'SELECT id FROM ta');
$ g. \# U+ q8 N4 F1 D5 v" i - while($row = mysqli_fetch_assoc($retval))* I# b) {6 z. S* \. w
- {
6 g% K$ X: p' o* ^( } - $id = $row['id'];- I0 g( E3 L* q5 D Z; A
- }
$ M, o; ^/ Q& B. b! Y7 T - ) E1 _ \5 p' f& O( c+ E8 H
- if($id > 0)
4 b! U2 h2 V/ z* ]' F+ R. n - { $ m6 V9 Z5 \' e; P
- --$id;
# W* y% _* U0 f% C - mysqli_query($conn ,'UPDATE ta SET id='.$id);
/ ~/ [' l4 ]; x3 { - }
: k# B- K' X, j) ~, |/ j - # php的文件锁,释放锁
$ i+ C; g3 X1 }( G4 ]% u$ |9 _ - flock($fp, LOCK_UN); 5 r& D8 P: y* D( ]* g, h' ?$ g
- fclose($fp);
, U6 {% g8 H5 F0 r
" A9 R- u8 x5 C# z/ g' U- // $res = mysqli_query($conn , 'SELECT id FROM ta');
* G5 }7 U+ g7 Y( c! y0 V - // while($row = mysqli_fetch_assoc($res))
$ Y, J. l6 H: n4 B - // {; W* n* a3 _% R! |* n6 d0 V( R: P
- // $id = $row['id'];
+ `7 x! D% C3 |7 L# X! D- t* Z. j - // }1 g# Y- s. r8 y
- // echo $id;
复制代码 " ?6 @9 o+ T+ |9 |! E8 Y7 I, _
0 D3 B( U5 l* x( K2 t8 s" l
抢券活动实例: - public function envelopeSnatching(){, o0 F0 d& k7 f: _5 g
- $lingqu = $_POST['type'];
6 C% m1 s$ \+ \. ]3 f - $uid=session('u_id');//用户id
- i" Z2 s" ?$ `$ k2 A' x - if(!$uid){
$ X* [; L9 P4 x. i1 e - $data['msg']='您没登录,请先登录!';4 b$ L H$ A0 K: N
- }else if(date('Y-m-d') != '2017-12-12'){( r2 t" A; Z+ X# s
- $data['msg']='不在活动时间内!';' x6 C. @4 w& s R! z- b8 Q8 }
- }else{
& ~6 t$ y7 N8 } - $hours=date('H');//当前小时数1 x$ z) N, F) y7 ?4 q
- if($hours > '09' || $hours > '17'){; h0 g! ^9 S1 `2 ^! l
- & Y$ u1 z" w0 j& a1 d9 i& {
- if($lingqu == 1 || $lingqu ==2){//点击10点的0 p- J3 w: C6 V2 a: g3 K
- if($lingqu == 1){
' W; _! W7 v8 Z) q& m - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过# y7 `* q- i# M4 M5 M
- if($hours > '09'){5 ^; m! r; q J6 y- h
- $num=mt_rand(25,28);//优惠券金额
P! ~) [& X1 e - $id=1;9 t& P4 y5 P z! b" |; K7 H
- }4 D) o# B* F3 s# _, e4 [
- }else if($lingqu == 2){
( p% D( b; |! g& ]- G6 K+ ~* o& f( Z - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
Q5 O1 K/ A" s2 V- c Z* H - if($hours > '17'){! ?1 ~8 Q! B9 Y: H) P
- $num=mt_rand(50,55);//优惠券金额6 b( F9 I, M, p9 v8 O
- $id=2;) @+ b% ~) G" q+ F' L2 K
- }# z" ~- g8 T0 i8 Q* q3 J3 e
- }8 o7 X) [5 G& F) f, d
- if(!$id){% ?0 e! D' ~2 j3 v
- $data['msg']='时间还没到,晚点再来吧。';
$ k+ {( d6 T0 b4 t9 h B) u - }else{0 i3 B, z' O9 U' _9 W4 W
- if($is_lingqu){
: p" R$ g$ Y n5 S2 e - $data['msg']='你已经领取过了,留点给别人吧!';' ^$ J ?: N' A# |
- }else{
0 R$ p$ V7 K) G& R, b3 p - //锁表) K$ b% J5 Q a, z9 s
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
; f! g) E! h0 t- @ - $active=M('active_num')->where(array('id'=>$id))->find();) `3 @4 _3 V3 [
- if($active > 0){
; f. c Y/ ~" E" g; W9 o5 j" G - //开启事务
5 B5 M1 T: M$ g4 a4 } - M()->execute('start transaction');
3 W/ }. j0 \* X' x$ H" r - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));. e4 ?! G! L( m4 t) d! D
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));0 Z" S$ W+ J0 ~1 ]8 G4 u4 x. J6 _* S
- $members_preferential = M('members_preferential');
2 } U6 \- B+ Z$ s6 K9 q9 ? - //对应投资金额,/ k$ @! j& H, r% ?; S% h
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
6 O! h4 L* g5 } }$ w - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');3 @( `2 l+ e' ^. N0 d' h5 @; `
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间1 f. ?- f0 }6 \0 F& B
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
! U5 L" J9 O2 n6 l8 \ - if($save && $add && $add2){# ?- a) D, q* |, g2 h* L: i
- //事务提交
" i" h3 q2 U7 O5 Q( { C - M()->execute('commit');
( s; ?: z5 J1 f - $data['msg']='恭喜你领取了'.$num.'元优惠券';
3 C( h# O( k' o* J5 J+ U E - }else{
* G3 C7 T& ?. G5 ~9 t/ \ - //回滚
+ j8 i# B# {8 M2 y# c - M()->execute('rollback');
) d0 E- m! A9 U2 E - $data['msg']='未知错误!';
2 o4 O2 I# T0 G4 G; T - }
! d2 i: K( _8 a& X# x - }else{
$ z. k/ ?, P) C8 P3 { - $data['msg']='红包已领完,你来晚了!';
5 p6 f. d( ?3 x9 r" X* ^/ x - }
6 O, t0 c$ j5 E; U+ [ }4 f - M()->execute('UNLOCK TABLES');2 p' F H; ?8 h; G7 \& O* u' Z5 o+ P
- }7 y$ V4 o3 W0 t$ v: d' \/ v
- }
7 ~2 K, l V3 \9 ~) D - }else{
3 W/ u+ Y) E; ]( e. S - $data['msg']='非法操作!';2 |2 S* P- O, n, V- T
- }) i7 f. m, N2 S9 {0 O) N+ `4 x7 b
- }else{" o g! }2 }; U" P+ x* k
- $data['msg']='还没有到活动时间,请晚点再来哟!!';
X6 ^/ z: Z8 U& H9 w1 T' R - }
7 `0 d, D$ P9 K6 j6 j( B" E! [ - }; e' k: w% x: S; y( D
- exit(json_encode($data));
g( U- D/ T# Q1 T" P - }
复制代码 3 p+ m# D; i! D4 f
+ w# U' M9 l7 Z% G |