模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
, C, h) s! [- l1 P) gMysql中的锁语法:
5 j( ^% t( d3 p: JLOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】
. ]% ^ K0 n4 X# _& ]) k, bUNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表& y7 K" _! a" Z; d+ y
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
, j. K% Y$ t0 [/ I8 R. O注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :' M& }% o" Z: A0 U4 N4 s
文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。
U% P6 E% ]4 T1 g" m" B测试时,有个文件就行,叫什么名无所谓 总结:
& w) p0 p0 D2 d$ a3 O% B; ?2 b) t项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
# H* o: w6 l$ `% `1. 高并发下单时,减库存量时要加锁- D. o, M9 m3 \7 g
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*
, n3 W" a: |$ ~% ^3 Z, x8 K& i - 模拟秒杀活动-- 商品100件# D! T$ f. e4 m" C7 c! i( `
- CREATE TABLE ta& t/ I" g: J! V+ L. ]
- (
: c V4 P: [+ U - id int comment '模拟100件活动商品的数量'
# V/ K% S- N: W - );
P) k5 {0 V m - INSERT INTO ta VALUES(100);2 v ~+ z0 L( A& S; o/ Y% o) }
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
) ^. L9 X% B5 ~. j- K - */ 6 a. {9 Z: O; b! A( k8 z
- * W4 A& }" q' y
- // 关闭错误报告. R9 ?: j8 f5 t
- error_reporting(0);
% b& y4 J3 B P$ G& v0 V/ O
+ X0 T8 C" t! [+ h6 `5 R: Z+ S- $dbhost = 'localhost:3306'; // mysql服务器主机地址' _" ]- h' f- r( W. W1 ?
- $dbuser = 'root'; // mysql用户名" H8 s1 M3 B0 ^5 {
- $dbpass = 'root'; // mysql用户名密码% d" T) M, V+ J" n
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
% i7 l U9 Y# Y, {% k6 X, E - if(! $conn )
/ V6 G8 b" X Y/ g - {
- l( i! {- r2 Z1 V+ [$ g - die('连接失败: ' . mysqli_error($conn));
. m) S0 I( B7 N: ~9 f - }7 i2 L2 \' {- E. Z2 H/ r( Z
- // 设置编码,防止中文乱码# @" n. V" L- @2 U- \( O
- mysqli_query($conn , "set names utf8");9 a2 _. R9 z. }7 y7 o
- mysqli_select_db( $conn, 'temp' ); 2 l1 l) j# J' y+ P) L, e' e
- " l" S) K! x6 r5 T7 b* {/ b
- # mysql 锁
9 ~3 W6 t8 U6 W8 h8 s7 E - mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
) B/ }* O5 c1 o+ D+ h/ y - $rs = mysqli_query($conn , 'SELECT id FROM a');
6 M5 O; d y7 B6 M1 w( j7 N - $id = mysqli_result($rs, 0, 0);
3 ] w; s/ k* v2 I2 X, k# ~ - if($id > 0)
0 O, {) V# Z- D1 X - { 7 Z; O6 W& s% `3 x* c- }, |7 n
- --$id; ( Q( H2 [& t: u# J
- mysqli_query($conn , 'UPDATE a SET id='.$id);
4 s; M8 q2 ~# L% W2 C+ ` - } & I# q4 b" L1 `
8 U0 y9 }, W& B3 |- # mysql 解锁 . y) q6 n O) C# b8 m H% `2 M
- mysqli_query($conn , 'UNLOCK TABLES');; Z g# S1 C/ ?2 |
- //查询解锁后的id值, D" T6 D1 [" v' w0 e) K! m5 i6 E
- // $res = mysqli_query($conn , 'SELECT id FROM ta');
8 u; J# v, |( x; `" w - // while($row = mysqli_fetch_assoc($res))5 f2 g; Y* p! T L e6 N" E
- // {
$ h* ]2 F5 Q; Y - // $id = $row['id'];
# m" {" a; y) a N* W9 \ - // }
6 Q3 k9 ]( L9 O; v5 X. k/ { - // echo $id;
复制代码 8 a% P3 g1 z5 ~9 w
3 s, s2 p& ], t7 S" K" l" P* }! x
0 }( s9 P6 U9 d. lPHP文件锁示例: - /*5 z- H9 w5 Z& n
- 模拟秒杀活动-- 商品100件
& V$ A6 T I* R/ m( L7 V/ l4 A+ l - CREATE TABLE ta5 _/ z8 O4 c# C% d3 S5 N+ t2 m
- (
* m8 R& d, x A! }) L n* q6 y7 y - id int comment '模拟100件活动商品的数量'
* Z9 q+ l) ?3 w# T; U+ \" i% O% W - );- r2 A( ^; ?! k
- INSERT INTO ta VALUES(100);
% Z7 D c( l2 w( i0 f+ t% [. k - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件
& n: ?% F. h, ?. H6 R - */
: @/ N: i6 d# N, A; C3 } - ' m4 t) ], J4 \6 A. r# Z
- // 关闭错误报告
+ k7 q- j1 t0 V# O+ I; ? - error_reporting(0); - K$ K! @6 }& V1 z
; i% C$ X" f: d9 h+ P- $dbhost = 'localhost:3306'; // mysql服务器主机地址$ K$ G0 t4 K+ ]
- $dbuser = 'root'; // mysql用户名
$ x; `4 D6 Q# u( }9 e6 [$ l6 G - $dbpass = 'root'; // mysql用户名密码
/ k8 u- Y# e, A% a3 x - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
: i, J, F1 }6 S- n1 R3 Y - if(! $conn )
t, F: p- x$ d# c; p' [- X - {
8 w( S' \4 M$ G% Z$ N% L- p - die('连接失败: ' . mysqli_error($conn));
7 W a! x c6 R1 g5 J! [$ h; W' A - }+ i' y- |# ]; H( ~8 [9 F- @
- // 设置编码,防止中文乱码
/ q: h3 y, t8 _# E, t# p - mysqli_query($conn , "set names utf8");
+ T' P. q2 f" b+ @+ g - mysqli_select_db( $conn, 'temp' );
' T2 u. p1 m7 [2 J4 q& ` - 6 W) \) b. s [$ {8 ]5 [" B
- # php中的文件锁 7 Y0 Z# K! _) I
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
+ e6 v5 G" Q) e - flock($fp, LOCK_EX);// 排他锁
- B0 s7 W% L3 x0 H - " @0 k) y+ [$ v3 {* M* l
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
6 e7 t1 C6 i) _ l - while($row = mysqli_fetch_assoc($retval))
* e) \* ]) l5 x' ? - {) n5 }! S V! N
- $id = $row['id'];; W: N( c# D: z8 q1 M
- }
. d6 T6 N% |7 I: d7 ~1 W' x6 o6 a7 R - ( f' o/ V% b( g7 ]
- if($id > 0)
- N( w" }9 Y- y+ y" a0 d - {
B; a6 E$ q: q; d& ` - --$id;
# X8 ?. P( w! u" _. d - mysqli_query($conn ,'UPDATE ta SET id='.$id); * J1 \2 P* x( }! @0 s
- } % ^, K( S5 s8 y& P
- # php的文件锁,释放锁
* k. P1 y) T) ^1 W* e8 H - flock($fp, LOCK_UN);
+ o; H0 f6 ^( ^5 ~# ` - fclose($fp);
8 ~* G( a7 l; E
* Y" t6 U* I! E* n6 [* C- // $res = mysqli_query($conn , 'SELECT id FROM ta'); M; _0 R5 L$ k) D
- // while($row = mysqli_fetch_assoc($res)): `6 G: @7 P- h
- // {) \; B" F9 h$ y$ x: t, g
- // $id = $row['id'];2 M: r) M. l# r4 R
- // }
, Z; F8 X5 H$ N3 J6 o% X$ I - // echo $id;
复制代码
) o+ Z2 s( w* {3 ~
5 Z( E C( K" _% ?抢券活动实例: - public function envelopeSnatching(){ _. `: L! Q7 |+ j
- $lingqu = $_POST['type'];
6 a/ f0 R) r$ ^1 N - $uid=session('u_id');//用户id1 s5 u) `+ t4 r8 u" x: Q( h
- if(!$uid){
# S) i. n5 D& k( h' O7 [ - $data['msg']='您没登录,请先登录!';5 a+ Y1 ~! ]3 j
- }else if(date('Y-m-d') != '2017-12-12'){
( a& x8 C, d6 e: ` - $data['msg']='不在活动时间内!';3 T% t: p! s* Y$ g
- }else{
- O" o8 u- [5 q2 ~0 z3 t8 x: w: p N - $hours=date('H');//当前小时数
- l# ]% ^- s% [' J) V1 L3 N - if($hours > '09' || $hours > '17'){
* ~5 Z. n* X, ]
: i& t) S) Q& M% \+ z) v- if($lingqu == 1 || $lingqu ==2){//点击10点的, n& g5 M) v# h9 T9 R7 S0 S, q2 u
- if($lingqu == 1){+ ]4 L+ }" U, N
- $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过' B S: y! E( l9 t* o5 r" }. ?
- if($hours > '09'){7 j) V/ K( y% K" O( W. |
- $num=mt_rand(25,28);//优惠券金额
! _ n1 @% }! v* r7 q6 B - $id=1;
8 I8 R4 r- ^" e% v# J6 P" n - }
& @# [/ _7 @0 ~ - }else if($lingqu == 2){
+ _; F: [' ]5 e0 E5 M% G - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();
6 ]0 d+ B* e) B; m - if($hours > '17'){
! x9 K, G5 J! k& J - $num=mt_rand(50,55);//优惠券金额! E2 y0 H7 R! B+ Z9 Z" p1 g
- $id=2;% m$ D4 E! k+ \) e! z/ p
- }
$ ?2 T+ x! V! |$ c - }
% j j9 ^( f; O; B: l" {7 u6 P - if(!$id){
' t% I* Z: P' v7 e* Q7 p - $data['msg']='时间还没到,晚点再来吧。';6 j- L8 |: O8 M! S
- }else{
- E1 _) q! g0 S( N - if($is_lingqu){& D' k( r4 S& [
- $data['msg']='你已经领取过了,留点给别人吧!';
. X" G; r) p1 Y* X - }else{+ s/ K4 L% |! o. l6 {
- //锁表& K3 ]8 T4 V- ?. L1 k7 e- T
- M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');
1 }7 W' P- A+ Y; d' G - $active=M('active_num')->where(array('id'=>$id))->find();7 p! @: u4 E4 u4 a% Z# e
- if($active > 0){; K! c. i# C. \, D' j& i1 |+ _; w
- //开启事务
1 }1 n N/ J5 H F( m0 @4 W$ j - M()->execute('start transaction');6 L* L$ |3 s' W# j5 s- \# ?# }
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));2 T; X% P$ Q; U/ c& Z
- $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));/ U8 Z+ f% U6 G0 q1 P
- $members_preferential = M('members_preferential');7 f3 p. R( {4 W* _
- //对应投资金额,: e3 ~5 X1 Q8 n: C# h
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));7 ~+ \" J" \1 b
- $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY');" J/ V: U% `+ v. C8 }7 P" ?% B
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间
$ i0 a7 J( D7 t% R9 ~( E& q - $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券( J: x$ L2 ]" F) a, \1 [+ R
- if($save && $add && $add2){
4 V" x) ^; W2 g9 G$ B0 b - //事务提交6 Q# m; T1 ~( [6 W. D7 ] e a
- M()->execute('commit');3 a6 B1 i9 |' M
- $data['msg']='恭喜你领取了'.$num.'元优惠券';
9 G w7 V* ~, v* E - }else{" M9 Q0 E+ c1 P! o7 x4 s
- //回滚& ?% r3 t0 U8 s: K4 N. a" |" y# T
- M()->execute('rollback');6 N3 l- S, u; c( [
- $data['msg']='未知错误!';
4 p% X( H) t5 ?( C - }
8 g4 {- |! U/ J6 V( }& i - }else{
! Q/ o& Z5 b$ g - $data['msg']='红包已领完,你来晚了!';
" A5 A$ z2 u) k$ R4 u g - }
# g' v2 G6 ?' \4 {, e2 m* ^' H - M()->execute('UNLOCK TABLES');5 D) G9 V9 a( {( X- }0 W
- }
! w' N2 M' c7 c - }
( u/ ]7 Q# V, a! z - }else{
" W" T+ k0 M+ O1 ~- Q/ K - $data['msg']='非法操作!';
; f; _" M$ a1 O7 w2 o. d - }- K' I) `7 B+ c0 Z4 G- @, v' c2 h
- }else{
7 T4 ~7 F1 a; {3 c. H - $data['msg']='还没有到活动时间,请晚点再来哟!!';
) c2 m" `. F( r* O. f6 U- B) l - }: w6 r( [6 F7 W& s0 u1 D, i% z
- }
# N3 g( k( ?0 `6 @0 C: i - exit(json_encode($data));
; x1 J% X$ M! \' F/ ^. E - }
复制代码 " m! t, a$ z0 D/ H$ G; e4 w
- W8 ^% x6 U0 a |