|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
7 y8 x' S5 H" \: G& X2 \7 iMysql中的锁语法:# I: `2 B) k' ]) x
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】2 w2 V, f2 W* a# o
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表! g* w/ ~9 M8 m
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
: |* B0 H0 r; T" ?; m) T8 j' y9 [注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
: z( a/ Q. |6 {6 B0 O文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。: C. y% S1 ^3 x' `; B% \1 N* E U# i
测试时,有个文件就行,叫什么名无所谓 总结: d. X1 f' e/ B, m
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
- f( z5 x# Q8 f. m+ h" y1. 高并发下单时,减库存量时要加锁9 r- _, K/ o) D* u4 Y% v
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
5 {9 T- O3 N+ e2 g - 模拟秒杀活动-- 商品100件 P. @3 f+ w# [) w! W: e
- CREATE TABLE ta
7 ^! ?+ _9 z9 E( @ - (
3 b4 J# I/ `* z& ? - id int comment '模拟100件活动商品的数量'/ `. |% j( W8 ]4 b% G$ Q5 B% @
- );
2 E ]7 P9 B8 G7 ^ - INSERT INTO ta VALUES(100);
2 @9 j% C' x1 b - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
4 l, R+ f; I- u - */
! ?( N5 b- e) K$ ?0 | -
$ D8 d7 c# V( k) K" R4 u$ I - // 关闭错误报告
2 }, p. y" a5 d1 ~3 y9 ]: U - error_reporting(0);
9 I8 _. U. h l. E j) c/ L+ \
5 u/ f8 F4 u* d- B1 S" t* `6 k3 \6 w- $dbhost = 'localhost:3306'; // mysql服务器主机地址5 a0 x( w: v+ o9 Z1 u5 c
- $dbuser = 'root'; // mysql用户名
0 q" N" V. Z% h" D - $dbpass = 'root'; // mysql用户名密码$ `1 V- `2 f5 K+ Q
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);( b$ d6 C) h1 E( n) B& y
- if(! $conn )0 R$ U, J5 s6 d# r/ I- K) ~
- {
. Y2 h7 n, ~! u' @3 V! u - die('连接失败: ' . mysqli_error($conn));
: x8 U! x% O7 y2 M9 l6 F" ^- T% C - }
0 v& P8 S( \" j9 B; p - // 设置编码,防止中文乱码3 i* R& ?6 M0 [, ]# n
- mysqli_query($conn , "set names utf8");+ F) m7 N- e( n9 H/ _. o2 s }
- mysqli_select_db( $conn, 'temp' );
6 a( ]: e/ I: Y# l, }
$ ?9 O0 M. k3 a6 w% ?, f: V- # mysql 锁 , H9 ?4 ]( G3 z1 ~" \( {8 x
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
8 o' t5 x$ ~8 ^$ B3 g - $rs = mysqli_query($conn , 'SELECT id FROM a');
) a# T3 `4 m5 V' C& G! Q - $id = mysqli_result($rs, 0, 0); ' Z+ A2 u5 R& @2 v
- if($id > 0) 6 {3 ]8 F# n j# A+ H8 w
- { 8 p9 j& M2 K- R4 S7 d7 L- t
- --$id; , p9 {: y0 @! I/ l8 }) Q8 x
- mysqli_query($conn , 'UPDATE a SET id='.$id);
! @* J# Y9 x4 X5 W4 ` - }
* j8 E) D' R* _1 r
# k# E( B: @# C7 ^! m8 Y, z- # mysql 解锁 " E# J$ C ?: z, k! {4 I& u
- mysqli_query($conn , 'UNLOCK TABLES');
1 c! z8 `- i* C* Y/ t - //查询解锁后的id值* J6 g% W1 ~+ u6 e& I* @. m: l
- // $res = mysqli_query($conn , 'SELECT id FROM ta');# |1 ^% N* ]2 ~. U
- // while($row = mysqli_fetch_assoc($res))
5 O! l8 u( g+ y& s& N# u6 v l - // {
' B' U, h" L, K. @2 P3 Y - // $id = $row['id'];
9 @! X2 F# r( O3 W+ h - // }% [' x! y9 E* P) I
- // echo $id;
复制代码 ) S/ r& a1 Q- {
& A$ w* `% f; K) T: R- m
, T. u0 W) ^+ v) XPHP文件锁示例: - /*
- A" I) {' i6 x, _ W; p - 模拟秒杀活动-- 商品100件* y s: c) x' _) F* ^
- CREATE TABLE ta: b. {+ G# L* q& n
- (
* p% V5 `. J' | - id int comment '模拟100件活动商品的数量'
7 _! C$ i$ D# I# A2 \, | - );
- M. f7 i' i# i6 n$ j1 H1 u - INSERT INTO ta VALUES(100);
3 N4 y! e* d2 Q/ ]& W% z9 J( w - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
' F+ ?! n- \ ]9 Q' P) W/ ^ - */
* b; q! C4 O1 K - - A. f* L+ t5 N* E' F. \
- // 关闭错误报告
3 a" S' [! ?1 ?- }) ~5 ?% U- W% i5 B - error_reporting(0); ; m1 x0 Q. q4 G: ~. w
9 F" J; N9 N- o% \3 c- $dbhost = 'localhost:3306'; // mysql服务器主机地址
( {) g7 F+ W; K" l7 }- f; N - $dbuser = 'root'; // mysql用户名, A5 L- G( J# P+ A* K5 T A
- $dbpass = 'root'; // mysql用户名密码
- f$ u# z: Q+ c8 y6 J& n; z- K - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);& P3 a! V8 T! Y7 E
- if(! $conn )
' n5 Q! D5 `, o' X4 g" b( ?6 z0 U$ K - {0 o+ D% U+ I* p, U- e: m8 b- o
- die('连接失败: ' . mysqli_error($conn));* d% ?6 s: v$ z9 ?6 r2 X0 a
- }: {: m) E3 e- w5 d- C1 Z6 v
- // 设置编码,防止中文乱码5 A* I. h) ]$ ]- T
- mysqli_query($conn , "set names utf8");! n6 y5 t8 }6 r0 a
- mysqli_select_db( $conn, 'temp' );
1 f- G* z, X K - 4 S( f3 f' G8 ?
- # php中的文件锁
6 B! s; v$ M% R$ v7 d+ B) r - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可 6 u) s* d, K: X4 @ i+ [
- flock($fp, LOCK_EX);// 排他锁
. [. C( L1 f A' p' N" ~1 J
! g2 M* a* D8 ~. {2 D- $retval = mysqli_query($conn ,'SELECT id FROM ta'); ( t9 l o z r* j3 L2 E
- while($row = mysqli_fetch_assoc($retval))
3 n$ |6 [6 N# g# b g - {, n* l% [- B0 P
- $id = $row['id'];% Q+ s7 d: K# H* M m
- }
! r3 A! T& P/ P" b - % \. N' \& d$ k1 V2 e
- if($id > 0)
5 H" g* r3 v! y* T1 D! R - { ; q# w" a3 Z% L: d( f9 w
- --$id;
: n4 x, H: O |- Z. _9 r G. r - mysqli_query($conn ,'UPDATE ta SET id='.$id);
0 J+ Y1 o ?, C1 E1 P" K, d" O - } / J( L. t, [. O
- # php的文件锁,释放锁
3 k) Z1 G, w9 M5 \( c! s - flock($fp, LOCK_UN);
5 S2 }) v1 S3 S2 J - fclose($fp);
/ g g, H" Z0 N/ a l
2 A( _- T& [7 L' e: E* N$ H, r4 N- // $res = mysqli_query($conn , 'SELECT id FROM ta');
0 s4 Q/ ~: [: i4 J9 V3 r2 K - // while($row = mysqli_fetch_assoc($res))+ M/ a6 h1 D" f& v
- // {
2 ?- u8 ~$ D& { - // $id = $row['id'];
1 Y+ ` ^* m2 }* ]8 V - // }" [7 f( R" B; x1 l- p
- // echo $id;
复制代码
0 r9 Z0 A& I/ N& @5 R! a
% B! l. b9 q% ?: K' T抢券活动实例: - public function envelopeSnatching(){
$ D) _5 I' l0 w7 x/ x - $lingqu = $_POST['type'];2 a2 a+ {7 v/ h2 P o9 Z3 q6 [
- $uid=session('u_id');//用户id0 Z3 F. _% v5 n- }. h
- if(!$uid){
; V9 D3 w* c1 q4 ~+ M, r7 q' P2 t/ e - $data['msg']='您没登录,请先登录!';2 \& K; O. X+ Q3 K( y
- }else if(date('Y-m-d') != '2017-12-12'){
) C, N& S- l3 ?2 t; C - $data['msg']='不在活动时间内!';) e3 R; b l' j [+ ~
- }else{
/ T. D1 ]- S5 A3 u) w+ C, L - $hours=date('H');//当前小时数6 Y' m" Z! R* N. J) S2 M+ x
- if($hours > '09' || $hours > '17'){/ ]5 {0 a2 t7 v5 I5 B
( e7 u- o3 @" j( J8 _1 u- if($lingqu == 1 || $lingqu ==2){//点击10点的) X* s0 l1 b; d8 `4 X. q) B- Y* A+ n
- if($lingqu == 1){: ^0 h2 [, d3 ?% X
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过, f1 v3 ?7 \. S. S
- if($hours > '09'){- \) n. Z* I! o" k* G9 Z" g( p
- $num=mt_rand(25,28);//优惠券金额
1 J, S# D- ~( T8 w* N - $id=1;
2 v+ D1 m% ]; @6 G - }8 E A# v1 l" }- r
- }else if($lingqu == 2){
% e' r! c# F% t/ \ - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();$ D9 e0 K' H f# M. q
- if($hours > '17'){+ B7 |/ `7 B- m C4 W$ O
- $num=mt_rand(50,55);//优惠券金额5 l- j+ }3 v. I1 ^) Q7 V a: D4 g
- $id=2;
" O' b4 d; W- @( r3 W. h - }
, i+ F9 c1 {: p& E - }
$ J8 ~5 n$ K1 [4 V3 Y0 H2 F - if(!$id){) X% f2 M; }; l* ]
- $data['msg']='时间还没到,晚点再来吧。';
+ h9 N! H. Z, E - }else{
! l4 J+ k( J, F* T7 G - if($is_lingqu){
5 F8 V$ n# k6 _9 f7 _) j - $data['msg']='你已经领取过了,留点给别人吧!';( Z2 N% ]: i8 l: l
- }else{9 E% N9 Y/ e. g# n% l# J; T, _
- //锁表$ j2 a/ n% B% U: x
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');1 n8 \, J; V6 m+ S
- $active=M('active_num')->where(array('id'=>$id))->find();
# B* t2 C: N. O X; I - if($active > 0){1 `3 x7 k; g8 p6 ^. l
- //开启事务
8 e! e# M! p% l& V5 i - M()->execute('start transaction');
" _) b9 l. H/ g* H' C( C - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));, Q: `/ }0 E8 x8 _: u
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));% m" b D' E" u
- $members_preferential = M('members_preferential');, {0 I3 a) c7 f
- //对应投资金额,/ D m1 d' o& g$ T5 m$ w$ i
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));: c, a o1 [6 ~) v% y, D5 r
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');
6 K) _! S. o- c0 k- Z5 T - $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间+ z8 w; U+ T& q
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券3 x- z h1 @8 m) q t8 M
- if($save && $add && $add2){
$ P/ T7 ^" @& b; C. x0 _" B0 J - //事务提交
6 Z' R# l# C+ {2 \ - M()->execute('commit');
U( Z1 w* T3 x+ \7 K7 Z - $data['msg']='恭喜你领取了'.$num.'元优惠券';
+ E& z- U, C2 L, `* w - }else{( U2 s, W% s S
- //回滚. m+ n6 G2 I' V8 U: I
- M()->execute('rollback');
2 e2 |: z! @9 ^- A1 [ - $data['msg']='未知错误!';
0 G$ V% I: |4 ^& @) d9 @ - }; ?7 \+ L" C g& u2 N$ k" S* L
- }else{# a/ w2 p7 |8 L0 C7 e
- $data['msg']='红包已领完,你来晚了!';
7 {4 v5 d- Z5 n7 G/ v% s- J1 v - }
$ ^. M, e/ N) k: y8 u( q0 V - M()->execute('UNLOCK TABLES');8 c" l5 R$ l: o, k0 n+ ~8 E
- }
$ j4 z& W3 m8 M; _5 s - }
7 d' g" J3 L% |7 u) Y% I - }else{( V% a w& ~* p# J
- $data['msg']='非法操作!';
% e- L: @$ z+ r+ z& J' f" K( I0 P - }
, X2 ]( D- F: V" j - }else{
@* ]: I3 M9 a7 D# S7 u0 K - $data['msg']='还没有到活动时间,请晚点再来哟!!';1 }. C3 q. A: v' v& N9 j+ S
- }$ i9 O7 Z ]4 r9 Z( j8 P8 B' k9 U9 R' v
- }2 n: N7 Y3 ]7 H# f7 i, Y
- exit(json_encode($data));
6 {$ b0 M% U K( _ O - }
复制代码 0 w$ K$ K. v- V
; }: D8 Q6 Y8 G% E \% L% b |