|
模拟高并发访问一个脚本:apache安装文件的bin/ab.exe可以模拟并发量 - C:\phpStudy\Apache\bin>ab.exe -c 10 -n 10 http://localhost/try.php // -c 模拟多少并发量 -n 一共请求多少次 http://请求的脚本
复制代码
) E" x+ V$ |' m& PMysql中的锁语法:2 I$ H- ?' @" v! o
LOCK TABLE 表名1 READ|WRITE, 表名2 READ|WRITE .................. 【锁表】! x- O: L( n0 D! A# U
UNLOCK TABLES 【释放表】 Read:读锁|共享锁 : 所有的客户端只能读这个表不能写这个表0 r$ N- [% J! P* W
Write:写锁|排它锁: 所有当前锁定客户端可以操作这个表,其他客户端只能阻塞
- B' h3 P; M* m% ?9 Y* Y- Q* W1 p注意:在锁表的过程中只能操作被锁定的表,如果要操作其他表,必须把所有要操作的表都锁定起来! PHP中的文件锁 :
1 l% _/ b$ m0 t8 u文件锁的文件与表有什么关系?:一点关系也没有,与令牌相似,谁拿到谁操作。所以表根本没锁。3 C3 b5 t: A1 H# ^; d& M7 M
测试时,有个文件就行,叫什么名无所谓 总结:
7 O* I' R6 \, d, }- {$ ?/ U项目中应该只使用PHP中的文件锁,尽量避免锁表,因为如果表被锁定了,那么整个网站中所有和这个表相关的功能都被拖慢了(例如:前台很多用户一直下订单,商品表mysql锁表,其他与商品表相关的操作一直处于阻塞状态【读不出来商品表】,因为一个功能把整个网站速度拖慢)。 比如在一个O2O外卖项目中,中午12-2点,晚上6点都是订单高并发时,这种情况下,MySQL锁显然是不考虑的,用户体验太差。其实根据实际的需求,外卖可以不用设计库存量的,当然除了秒杀活动模块还是需要php文件锁的。 应用场景:
9 v! H# k( b3 W- q4 f1. 高并发下单时,减库存量时要加锁2 D* q: U3 r T
2. 高并发抢单、抢票时要使用 Mysql锁示例: - /*+ \2 v' f# f3 L, |- `, z( m
- 模拟秒杀活动-- 商品100件! m4 ^& `; R3 i% H. @' q9 J
- CREATE TABLE ta7 R1 l& r1 Y0 E
- ( R m7 j# C* u' X
- id int comment '模拟100件活动商品的数量'
- F8 \# R3 m2 J$ {/ r/ ` - );
, q: C( v1 d+ G! S8 S' p ^ - INSERT INTO ta VALUES(100);" q' P# C: d' _$ y
- 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件/ P% |& A5 T% s% ~& T% `* o
- */ 1 G: [/ u; ^8 E3 C, c! w) M
- 6 D6 R, V$ t7 q# b7 \& V* s l# g" d7 E
- // 关闭错误报告
# ]" c" o# a* `( q* Y3 _" Y: E - error_reporting(0);
( M* F# J; a* b) M- p# N
& a! t: Y% w+ E: x- |- $dbhost = 'localhost:3306'; // mysql服务器主机地址
4 p5 r- N8 s+ G* i: ?8 V - $dbuser = 'root'; // mysql用户名$ y! s3 |9 a" u' j
- $dbpass = 'root'; // mysql用户名密码% \+ l4 J0 ~" r/ e
- $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
* b* s0 [% R' ^% x7 _* c: c% W' l - if(! $conn )
7 F0 V, @4 z8 ~% l - {
$ P8 B% d- B- J* ` - die('连接失败: ' . mysqli_error($conn));
" a# i5 D; W4 ]& z3 S# k+ D- R - }
& W. Y, c; i# ?5 W& L, s* { - // 设置编码,防止中文乱码
; G* S/ c! I, e( P( _: ~. @6 J - mysqli_query($conn , "set names utf8");! D: L+ j: }5 B. c; j( [
- mysqli_select_db( $conn, 'temp' );
% h! N3 d7 N5 E. i5 G8 ` - & \) L/ J* i P$ L/ c! ]# i- W0 |
- # mysql 锁 2 R* {, D0 H# a" w3 i
- mysqli_query($conn , 'LOCK TABLE a WRITE');// 只有一个客户端可以锁定表,其他客户端阻塞在这
7 h8 o# U+ R. _6 z - $rs = mysqli_query($conn , 'SELECT id FROM a'); 3 U* s! e L1 h, |) r. j7 O
- $id = mysqli_result($rs, 0, 0);
; |- f( v1 l! i; g9 ]/ ]- \: ?$ V$ Z - if($id > 0) 9 o; X8 B7 R/ h- |& A9 Q; N
- {
; {5 I8 p; o4 B- J' u# S - --$id; ( m/ {$ m$ e1 p" i3 N
- mysqli_query($conn , 'UPDATE a SET id='.$id); 9 ~6 w* Z& r3 ^) U/ P, s! f% C
- } 1 D; e8 t7 W. o, E* h, r
- 2 k K/ F5 W {5 r
- # mysql 解锁 & }- a% ?& H- g. `, Q
- mysqli_query($conn , 'UNLOCK TABLES');7 l* b; F+ Z- t8 M; J
- //查询解锁后的id值
& O9 S8 Y; j! W. e: `, V, @ - // $res = mysqli_query($conn , 'SELECT id FROM ta');/ z2 s4 u, u0 R- j3 ]
- // while($row = mysqli_fetch_assoc($res))
( S/ Z0 B9 H i7 H! h: O U# Z - // {
, ~* v' y; q4 B - // $id = $row['id'];
* z" i# D; d6 w, ]8 H3 Z- C - // }9 k) Z0 t0 m1 G6 }6 N7 m& b3 N7 D
- // echo $id;
复制代码
+ {( g# G. B4 M9 i# j) x; |# G3 g# j T$ M1 f
+ w. q0 F) {( Q" F1 j- GPHP文件锁示例: - /* S1 {8 ~: q( h" Z4 c& P* U
- 模拟秒杀活动-- 商品100件 n+ t7 o* @& m
- CREATE TABLE ta, |* ~4 @2 {8 w# D( |5 G
- (+ o* D) L6 r+ z0 V" ^9 N1 ~
- id int comment '模拟100件活动商品的数量'
+ f8 N" n7 B# X* j+ W$ M5 z1 t8 c8 I - );
. S/ M7 t) L; r+ A4 L7 v - INSERT INTO ta VALUES(100);
* |* C0 J0 |6 R2 ~$ Y. i+ P9 j - 模仿:以10的并发量访问这个脚本! 使用apache自带的ab.exe软件! T& {1 h" P9 O4 @" x6 t- R3 a
- */ ' L8 S5 ]- f' [+ c4 {
- * e! |" r$ o3 @
- // 关闭错误报告
! R* I |" t0 O' z9 H: { - error_reporting(0); ) G3 ~. W1 I" W& P6 W2 P( l: ]
- ; L, a* C' S6 f4 Z; r; R3 k
- $dbhost = 'localhost:3306'; // mysql服务器主机地址- A6 L/ {; V! F. v+ e
- $dbuser = 'root'; // mysql用户名& j8 [& {: I; R4 w( m9 `
- $dbpass = 'root'; // mysql用户名密码
( z- }* H$ J! D" {' h( @" p - $conn = mysqli_connect($dbhost, $dbuser, $dbpass);
" Y, a/ R! b$ S1 Y8 ^8 M - if(! $conn )( c0 X1 X2 Z5 ^$ f
- {
+ ?: J6 o3 ?- Q2 @/ M7 Z - die('连接失败: ' . mysqli_error($conn));
6 B2 ]; m" x# V& Z8 K - }/ g( W2 O3 q) S. G
- // 设置编码,防止中文乱码
3 A+ o2 ^4 h4 |9 T - mysqli_query($conn , "set names utf8");
! K& u9 P: G+ i" A: E6 i# | - mysqli_select_db( $conn, 'temp' ); }1 `5 x* Y# Y4 k+ B) w
& J) A! T/ S1 A3 ~+ J" _/ N- # php中的文件锁 ; r: ?( r% L# q
- $fp = fopen('./a.lock', 'r'); // php的文件锁和表没关系,随便一个文件即可
' K( m% x- W0 V1 u - flock($fp, LOCK_EX);// 排他锁
* U* V4 l) x1 u" D - 0 @ W# M1 Q# R- A3 X
- $retval = mysqli_query($conn ,'SELECT id FROM ta');
$ z v8 H; I5 t - while($row = mysqli_fetch_assoc($retval))
) e; r' [4 R% j9 |9 I - {
5 q9 |2 m3 Z: Z) x - $id = $row['id'];, c' R, _0 u- E; q, j
- }
) e# \/ a; x) D2 y/ J& ^8 l; n+ ^ - 8 r3 c9 @9 v+ p7 r& U2 q
- if($id > 0)
8 [% H3 u) M; u9 o% P6 ^5 [$ R# h - { 0 [" D; y2 M" F& D
- --$id; ) n0 F. O ~5 B+ I/ [" r( L W( B
- mysqli_query($conn ,'UPDATE ta SET id='.$id); : C T8 z% `5 M; t3 E! ]
- }
1 r! a; Y9 S; }% T( B - # php的文件锁,释放锁 ( P4 u3 T, j0 W, Q0 I) o
- flock($fp, LOCK_UN);
5 e% m# k+ e0 m5 H - fclose($fp);% n! ]. v; L. y/ Q
- , M$ E+ ~% L5 u, M0 d- B
- // $res = mysqli_query($conn , 'SELECT id FROM ta');5 x9 k8 V7 Z2 w( j, c/ x4 l0 q
- // while($row = mysqli_fetch_assoc($res))
% Y* `. @6 A) @) [, b - // {
0 t7 [# @- F# E8 a - // $id = $row['id'];
5 m% \3 A8 m' M - // }0 S" P' F( Z' ?- i
- // echo $id;
复制代码
$ J3 _7 o! B# ^
& I/ L; X9 w1 [) F抢券活动实例: - public function envelopeSnatching(){1 G) j; X: k! u; a c
- $lingqu = $_POST['type'];
; l$ D7 F: |8 A - $uid=session('u_id');//用户id) ]6 p! Z0 P, ?
- if(!$uid){
2 d! b; q" x; J( w2 G* W7 O - $data['msg']='您没登录,请先登录!';; `4 O7 U3 F1 S3 j9 D
- }else if(date('Y-m-d') != '2017-12-12'){
2 i; a$ h6 \# [9 y - $data['msg']='不在活动时间内!';8 `, ~; ?) w. W
- }else{
" }3 ?& N7 j* p: v N8 o1 H - $hours=date('H');//当前小时数; ^( r* m1 M6 S$ O f# P
- if($hours > '09' || $hours > '17'){6 G @# ?- V; K
2 W, C' h7 t$ u2 Y3 G/ X2 p- if($lingqu == 1 || $lingqu ==2){//点击10点的9 M W0 }, Z4 p
- if($lingqu == 1){
T5 x# j4 w9 v! K - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>1,'uid'=>$uid))->find();//判断是否领取过
6 L, W& i8 g0 v( |* [ - if($hours > '09'){
; Y9 y! `) A" ] - $num=mt_rand(25,28);//优惠券金额
1 g3 t1 H7 v' x9 e+ h( O' B9 x - $id=1;9 z! y( c2 D. B1 c
- }
0 V/ y, e: {$ X6 j; \ - }else if($lingqu == 2){
5 g7 Z' G3 u" u4 h - $is_lingqu=M('active_log')->field('id')->where(array('num_id'=>2,'uid'=>$uid))->find();; k- r: R4 g& V' |2 \& K9 M4 V' O
- if($hours > '17'){. u. @3 B( O5 H, z5 W
- $num=mt_rand(50,55);//优惠券金额% C6 i4 i7 x N& L% J: `
- $id=2;) d2 P7 G! r7 T& b! r, |/ F
- }3 w! C+ q( L2 f( G& R- H' F
- }% N X2 R5 q( J. o
- if(!$id){
3 p" N4 b5 u* V5 D4 t( P* a4 @ - $data['msg']='时间还没到,晚点再来吧。';* e, D }: B: y. z1 C
- }else{# g- r: N* S3 Z4 m* L
- if($is_lingqu){7 N, c; H% n% q6 y$ s
- $data['msg']='你已经领取过了,留点给别人吧!';
7 p1 S9 ?& f' H - }else{8 L5 G9 h9 {! p
- //锁表
4 X: p4 j/ u$ {1 Q" i6 ` - M()->execute('LOCK TABLE active_num WRITE,active_log WRITE');9 ~ f0 A+ C5 Q! s+ n2 o* h* l+ Y
- $active=M('active_num')->where(array('id'=>$id))->find();
9 }* g& ?. i: U1 [0 D - if($active > 0){
+ L8 H9 U/ L$ X/ z8 \5 |4 J - //开启事务" |5 }- b" e9 a% D
- M()->execute('start transaction');2 `# n" @) M+ ^: U4 L+ w1 }
- $save=M('active_num')->save(array('id'=>$id,'num'=>$active['num']-1));
) q) R& z1 m% } - $add=M('active_log')->add(array('uid'=>$uid,'money'=>$num,'num_id'=>$id,'addtime'=>time()));, M) d+ m0 T" ?+ F0 U: x
- $members_preferential = M('members_preferential'); ]- N5 A1 A( S: C: z
- //对应投资金额,# {. R' ]' ~6 ]# G( N/ l; z
- $key=array_search($num,array_reverse(C('PREFERENTIAL_JL'),true));
: o8 r) o4 Q& A6 o, f" Y$ {; H! ~ - $PREFERENTIAL_ENDDAY=C('PREFERENTIAL_ENDDAY'); C% u- U( V- `3 Z! \6 z
- $endtime=strtotime("+{$PREFERENTIAL_ENDDAY}day");//过期时间/ t2 c8 Z C! x& C1 L
- $add2=$members_preferential->add(array('uid'=>$uid,'type'=>$key,'endtime'=>$endtime));//添加优惠券$ G8 b& |; _& E5 o
- if($save && $add && $add2){
# J$ Q1 `. v. y/ @ ^: h/ P - //事务提交- L5 U' O2 p4 l4 o9 Z0 }
- M()->execute('commit');9 h7 ^) N- X, |8 k
- $data['msg']='恭喜你领取了'.$num.'元优惠券';1 w* }6 y! [% J, E4 Q+ s
- }else{
8 q* P9 `5 ^/ w5 D+ N! a - //回滚6 o! n+ g( O7 |! h8 X B
- M()->execute('rollback');1 i6 H9 u; U$ X* E% Q2 @# _
- $data['msg']='未知错误!';% R. v1 d6 a% Q
- }. k/ e" N3 c8 O- F
- }else{) ~* h9 i/ P( n; E* _
- $data['msg']='红包已领完,你来晚了!';. @3 \/ i# i N! X! D
- }" S6 K+ G* L. f/ [& }% P
- M()->execute('UNLOCK TABLES');
! T" H" O* Y- H, X5 r$ q$ j# Z - } K5 ?6 ]: h Z Z: B6 y
- }
$ ]# @% ^' k6 E3 ^& t - }else{
# o1 s' s0 o3 ?9 } t1 ? - $data['msg']='非法操作!';7 p' J9 r4 U e/ @( p- [
- }7 `7 |! D; f, h7 c, X0 t/ N; q% _) H& M
- }else{
6 q, A- }% P& h% y. c - $data['msg']='还没有到活动时间,请晚点再来哟!!';. J& G0 Z0 W. q& q: M) e; F7 ~; |
- }) Q! Q `( t+ b# P" W8 Z3 r
- }
5 [$ u5 A0 t c$ m' Y$ m - exit(json_encode($data));+ a* ^( M. z2 m4 s( t
- }
复制代码
2 I8 e' J' B5 ~; |$ T7 |- l- z2 |7 {: [* j/ D) X' c, K1 a. H
|