模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码 0 m: k6 P3 v8 z |1 K7 t* u
Mysql中的锁语法:
( w$ y6 @/ e5 x; A! l; l4 DLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
7 Y5 G* w% ^# G/ X! QUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表
v |, z4 [; f6 DWrite:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
# o2 G% H: [. o% P; @; B: s注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :: k0 I& N4 G: p4 N
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
& E" U% |! K4 w+ a0 F3 L测试时,有个文件就行,叫什么名无所谓 总结:$ o3 K- }* h Y
项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
0 r* e B8 @, a: @" j0 c- u2 i0 \1. 高并发下单时,减库存量时要加锁0 D6 o- l" o! J& p) O
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
2 T* @4 f( t t* R/ V - 模拟秒杀活动-- 商品100件7 R, e) Y8 @- s/ w8 [ j3 Y
- CREATE TABLE ta
! B( w+ H% ]& r8 u5 K- B& A - (# q0 C2 g4 N, ]% g
- id int comment '模拟100件活动商品的数量'2 n7 h3 z7 P" S/ z7 R
- );
# B3 k% z7 ^2 |8 Z, q - INSERT INTO ta VALUES(100);& f7 m+ Q2 ~# f
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
8 `: K, t! _, s: o - */ ! k6 s5 _/ K$ }4 P
-
; l E+ b' i- f9 }1 F' j - // 关闭错误报告) A4 i$ t& a7 L. P- m) Y7 H( a( x
- error_reporting(0);
5 S! i7 B+ w* f2 n m7 B
( j- e8 V6 U. u& ^! B- $dbhost = 'localhost:3306'; // mysql服务器主机地址1 u( c5 Q$ t0 a8 Y
- $dbuser = 'root'; // mysql用户名0 R5 @5 k# C9 {3 ?" i7 [- n
- $dbpass = 'root'; // mysql用户名密码
a' F) \' v0 J! s; N - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
a7 P% z5 W: U* c& `( I - if(! $conn )9 j3 z G+ s1 w* l5 u
- {
1 S- ~3 v1 E1 q/ f9 P( w - die('连接失败: ' . mysqli_error($conn));
: F6 v) Q, S! r1 d d - }# b& u" l1 v0 F7 l
- // 设置编码,防止中文乱码& v A' H7 H( p# a2 f, x
- mysqli_query($conn , "set names utf8");, @; O% ^4 Y" _/ H
- mysqli_select_db( $conn, 'temp' );
- L& _6 m. U# M6 w: \, b/ N
' i1 }9 ~0 f5 ~( V! S9 m, j2 Z- # mysql 锁
/ y% J u% ^7 ^9 m - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
- @! m% H K! C9 J6 g - $rs = mysqli_query($conn , 'SELECT id FROM a');
7 ]# L! b1 _) _: ~! b5 s; `- | - $id = mysqli_result($rs, 0, 0);
+ [+ z/ Z5 o0 Q9 g0 |0 f( Y - if($id > 0) * ^4 T8 _3 V, J- \
- { / h. C/ R, s( z
- --$id; X" t' N7 B- B: N
- mysqli_query($conn , 'UPDATE a SET id='.$id);
/ K; d5 R6 b0 j. f - } 1 L. V8 W! F1 c0 l }# G1 o9 B2 R: L
. l7 {! d7 Q- { z; i* }- # mysql 解锁
, \1 O% p: Y4 W( Q - mysqli_query($conn , 'UNLOCK TABLES');
' s! G- Y3 e) x4 q - //查询解锁后的id值
% f3 _1 ?: M% l) a& p) F9 i - // $res = mysqli_query($conn , 'SELECT id FROM ta');
' H$ X! {, h W+ U# R! l - // while($row = mysqli_fetch_assoc($res))4 p0 d/ i( M: A" `; X+ J
- // {
8 E( K, w4 P+ O - // $id = $row['id'];1 }4 b h$ K! D1 P7 o
- // }6 K/ F, s6 C2 D/ j- g$ A+ W
- // echo $id;
复制代码
/ |0 m# Z0 V/ y3 D0 K( q' [$ H% M% I
5 N7 P. u/ Z/ }2 n5 a$ g
PHP文件锁示例: - /*
$ P7 N+ D. P% e7 Z T - 模拟秒杀活动-- 商品100件
7 G/ @& z/ c9 E& u8 y# b. Y- v5 O) S - CREATE TABLE ta8 U& W- ^# J$ [; ^
- (
) _8 T! g$ F% d0 p - id int comment '模拟100件活动商品的数量', \, w# X2 z5 D, k
- );
/ s4 B3 Z7 w9 f$ c" e - INSERT INTO ta VALUES(100);
" F U4 B8 B9 P8 i8 z - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
* U: }4 E1 z7 w: ^( S - */ ; ]2 j, h% m4 v t8 D- m
-
- @! Y* h* h t - // 关闭错误报告
( e8 r# K; l4 H5 K# f - error_reporting(0); 3 O8 j0 z1 |8 @3 u
- 7 }4 E* ] h) B. |. L: F1 _
- $dbhost = 'localhost:3306'; // mysql服务器主机地址0 A7 b( g- ?: |$ |, f4 G; Q
- $dbuser = 'root'; // mysql用户名
$ S* X/ I4 S: D9 w8 L - $dbpass = 'root'; // mysql用户名密码
2 f- E( |# X2 f' J/ g8 V9 `" ]$ D - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);/ y5 e* r" I6 ^; L4 Y
- if(! $conn )
, a5 u8 o5 k: O& z% T' P; z x7 q; u; @ - {
8 X& x$ k7 I5 U2 N7 K" L- l - die('连接失败: ' . mysqli_error($conn));
6 ]0 X7 r V4 @7 G9 h: p% E - }
4 u! t) e1 \5 W; d: T - // 设置编码,防止中文乱码4 B& c5 M, g; t% I" F& N( V6 w; z
- mysqli_query($conn , "set names utf8");# B+ O$ v' V% ]( m0 p' E
- mysqli_select_db( $conn, 'temp' );
$ }- R" D3 f: Y; U
! w3 `; \; U1 J# J/ t- # php中的文件锁
3 W. `2 y. R" _' j6 R8 q2 F - $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
9 _& c$ L( o8 @0 Q; l& l8 ^/ E - flock($fp, LOCK_EX);// 排他锁
1 x, ] P; H# h7 o2 J2 b0 N! f - & s: j9 k; X( c# n9 e I
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
1 ?. g' B" t3 s* G+ r* k - while($row = mysqli_fetch_assoc($retval))
2 c5 F+ j: b5 l" R/ y6 P, D - {
8 H$ O: a7 K0 c/ _/ @% F4 N" V - $id = $row['id'];
8 B0 U& T9 ]# o3 W! K" Q - }
* E0 c: g7 e1 `: f. |' U1 h8 @ - $ o. p6 x3 Y @/ o$ S
- if($id > 0)
% I2 v* n3 ~. Y - {
- k2 d# `7 V0 A# J# r - --$id; * a1 t: x' |) _3 M
- mysqli_query($conn ,'UPDATE ta SET id='.$id); ; z2 d# l/ I/ A* [! d: f
- }
) R) c+ e- t9 A+ ~$ M5 C - # php的文件锁,释放锁
$ j1 Y S2 T+ Z" `4 n6 k8 z - flock($fp, LOCK_UN); W" ~! Q: \3 \, Y X1 U0 h! C3 e3 S
- fclose($fp);& ^; F& Q; S* }- @ L; Q" R
2 s& F" Q( e- b& z5 M9 ~) `- // $res = mysqli_query($conn , 'SELECT id FROM ta');
' Z+ U; c1 E; k" |3 _ - // while($row = mysqli_fetch_assoc($res))& R2 ^7 S* Y* G o% Y# q
- // {
4 q0 Q8 B& Q9 v" I* m0 u* h1 V - // $id = $row['id'];
) o" o ]6 e3 p# c( [( Z - // }% D3 \# |& e7 P
- // echo $id;
复制代码
3 g" s1 `$ x- M/ V
# C& }0 Y1 X1 p; I5 }5 H5 e抢券活动实例: - public function envelopeSnatching(){
' N5 w, z. {# R0 L - $lingqu = $_POST['type'];
4 @" U& O! ?6 F% C - $uid=session('u_id');//用户id+ c& D& I4 Y W8 k' u
- if(!$uid){/ {& P h" `, l& M; I% x* f+ |* v
- $data['msg']='您没登录,请先登录!'; X) q1 d- T, r( u3 {4 O
- }else if(date('Y-m-d') != '2017-12-12'){# e* P6 z' o3 h# q
- $data['msg']='不在活动时间内!';7 u' ], h f9 I! v& b
- }else{
3 ~3 g6 ~( f+ P+ U; ~ - $hours=date('H');//当前小时数5 s D# M, N4 |. ~/ X1 i
- if($hours > '09' || $hours > '17'){" |7 ~: f: c! A' |6 _. R
- , S/ n8 a: c; T& ~
- if($lingqu == 1 || $lingqu ==2){//点击10点的
5 c; `8 K) G1 d* `8 ~ - if($lingqu == 1){9 k6 v6 q- P3 x$ O
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过( [* H5 A8 J/ ^0 B; j7 T
- if($hours > '09'){
' q" d* e# s; d7 J7 y* S. P9 Y - $num=mt_rand(25,28);//优惠券金额
- r+ M$ {, I% X! P - $id=1;3 y1 J' d7 ^) B. Z/ o6 ^
- }
& _4 m* c) s7 g/ ~6 t% ~ - }else if($lingqu == 2){+ @- P1 E7 O" q$ w1 O
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();$ w' F) M& ~; B6 n
- if($hours > '17'){
6 X, b% @* E0 V! k. |, U) f1 r - $num=mt_rand(50,55);//优惠券金额
' J J# F$ j! Y4 N( O% X9 R - $id=2;6 H% Z% k# R, c. r. ` v0 V
- }' l$ w6 j' R1 t) f
- }
. l% x8 y+ L) Y - if(!$id){
3 ], ^. B) h+ Z, _ H& I+ v - $data['msg']='时间还没到,晚点再来吧。';4 i& h( `- k3 o: o
- }else{
7 [! P$ p; p- @% @' d: u - if($is_lingqu){
9 K6 `3 w2 j0 U$ } - $data['msg']='你已经领取过了,留点给别人吧!';# G% l* h! I! D& U) m$ P" ?% p
- }else{, d: S* {9 W* j" A# c
- //锁表
) p9 z% D1 |1 E& U) R% D: |1 F - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
: P+ m; H% ~) |: l; o1 _% D - $active=M('active_num')->where(array('id'=>$id))->find();% Z9 r+ m: n9 } c+ o
- if($active > 0){# h# R# Q& F& H) s/ |' T1 P
- //开启事务! o3 f9 ?) D( M
- M()->execute('start transaction');
7 M e7 u: B c5 v/ p+ P - $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));' z% R. L5 e3 [, W1 k! V
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));
( l7 ?' n) U2 M: }8 b, F! e - $members_preferential = M('members_preferential');/ M5 N7 a$ u! O' Y2 C
- //对应投资金额, V1 c" v2 j- b$ e" j. J' L
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
( o- X5 W' {4 h5 r! r - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');: Y2 e4 J5 \7 q- ~* r# r% w
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
4 Y$ @! S8 E. D/ i) A& | - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券
- N" h$ N! y4 { - if($save && $add && $add2){
' A9 {8 S8 k. ] - //事务提交$ V/ C: {/ U# X- E8 t. V( S
- M()->execute('commit');
2 U, ?' Q' X( w) }* d* M - $data['msg']='恭喜你领取了'.$num.'元优惠券';1 h; m/ b* T* u* }1 ~1 l P+ K6 U: @
- }else{1 B$ @& L6 K5 ~" ]7 d5 G+ f
- //回滚
' g) ~; m3 z9 h/ N( ^* Q, r( W - M()->execute('rollback');
9 l% E k5 N1 E; ? - $data['msg']='未知错误!';/ p( R9 b( B; @& T6 Z" E0 u
- }
# H" n! S0 [% S. q1 g- ]# l - }else{; |3 h( o8 j( s8 c8 S
- $data['msg']='红包已领完,你来晚了!';* K3 q0 k3 G" i
- }
( F g4 `' v2 T( W8 O& i! G) @ - M()->execute('UNLOCK TABLES');/ Q) J6 c" d8 {( f6 \* H
- }
% C6 @6 j% Q3 \! H8 d5 _ - }
( ?3 U( { g/ q# n9 v! n' C( w - }else{
; H- @% `3 G* y3 ^& C - $data['msg']='非法操作!';0 T" `( Q v" L# u1 w, a
- }
$ P0 B6 Z" h. t8 X0 [: ]$ ~ - }else{
4 t2 G* z1 C* k+ v- M - $data['msg']='还没有到活动时间,请晚点再来哟!!';
1 l$ j; A/ _. z" o. o - }
/ c1 I) p% ]( X6 R. b, R! L - }/ j, O% w; Q$ ?) P5 j
- exit(json_encode($data));
& B* B5 U. V" q! N, F - }
复制代码 , n; j& K% w; T+ p0 X" P
9 `+ E/ g0 N2 R: G8 `7 v
|